DocsPython SDK

Python SDK

forgein — sync context in any Python agent or LLM pipeline. Sync and async clients, Anthropic / OpenAI / LangChain integrations, 22/22 tests green.

PyPI ↗GitHub ↗

Install

pip install forgein

Optional extras:

pip install "forgein[langchain]"   # LangChain tool integration
pip install "forgein[cli]"         # forgein command-line interface
pip install "forgein[all]"         # everything above

Requires Python ≥ 3.9. Built on httpx and Pydantic v2. Fully typed with py.typed.

Authentication

export FORGEIN_API_TOKEN="fg_..."

Get a token at app.forgein.ai/tokens, or via the Claude Code skill:

/forgein auth

You can also pass the token directly: ForgeinClient(token="fg_..."). The environment variable takes precedence over the constructor argument.

Adapters

from forgein import ForgeinClient

with ForgeinClient() as client:
    # Fetch context string for one adapter
    context = client.adapters.get("copilot", project="my-saas-app")
    print(context)

    # Write all context files to disk
    result = client.adapters.sync("my-saas-app", path=".")
    print(f"{len(result.written)} files written, {len(result.skipped)} skipped")

Supported adapters:

copilot     → .github/copilot-instructions.md
cursor      → .cursorrules
windsurf    → .windsurfrules
claude-code → CLAUDE.md
gemini      → .gemini/context.md
chatgpt     → .chatgpt/context.json
MethodReturnsDescription
.get(adapter, *, project)strFetch context string for one adapter
.sync(project, *, path=".", adapters=None)SyncResultWrite context files to disk
.usage()AdapterUsagePer-adapter usage stats and 14-day sparkline

Memory

with ForgeinClient() as client:
    # List files (no content)
    files = client.memory.list("my-saas-app")

    # Read one file
    f = client.memory.get("my-saas-app", "context/stack.md")
    print(f.content)

    # Create or update a file
    client.memory.put("my-saas-app", "context/stack.md", "## Stack\nNext.js · Drizzle · Postgres")

    # Delete
    client.memory.delete("my-saas-app", "context/stack.md")

    # Full-text search
    results = client.memory.search("Drizzle ORM conventions")

    # Context health — stale files, missing sections
    health = client.memory.health()
    print(f"{health.stale_count} stale files")
MethodReturnsDescription
.list(project)list[MemoryFileMeta]List files without content
.get(project, path)MemoryFileRead a single file
.put(project, path, content)MemoryFileMetaCreate or update a file
.delete(project, path)NoneDelete a file
.projects()list[MemoryProject]All projects with file counts
.search(query)list[SearchResult]Full-text search across all memory
.stats()MemoryStatsAggregate counts and byte sizes
.health()MemoryHealthStale-context detection
.history(project, path)list[MemoryHistoryEntry]Version history (up to 50)

Async client

import asyncio
from forgein import AsyncForgeinClient

async def main():
    async with AsyncForgeinClient() as client:
        copilot, cursor, claude = await asyncio.gather(
            client.adapters.get("copilot",     project="my-saas-app"),
            client.adapters.get("cursor",      project="my-saas-app"),
            client.adapters.get("claude-code", project="my-saas-app"),
        )

asyncio.run(main())

All methods on AsyncForgeinClient are identical to ForgeinClient but return awaitables. Both clients support context managers (async with / with).

With Anthropic

import anthropic
from forgein.integrations.anthropic import get_system_prompt

client = anthropic.Anthropic()
message = client.messages.create(
    model="claude-opus-4-8",
    system=get_system_prompt("my-saas-app"),
    messages=[{"role": "user", "content": "Refactor the auth middleware"}],
    max_tokens=8192,
)

get_system_prompt(project) fetches your forgein context and returns it as a plain string, ready to pass directly to system=.

With OpenAI

from openai import OpenAI
from forgein.integrations.openai import get_system_message

client = OpenAI()
response = client.chat.completions.create(
    model="gpt-4o",
    messages=[
        get_system_message("my-saas-app"),
        {"role": "user", "content": "How should I structure the Stripe webhook?"},
    ],
)

get_system_message(project) returns a {"role": "system", "content": "..."} dict you can unpack directly into the messages list.

With LangChain

from langchain_anthropic import ChatAnthropic
from langchain.agents import AgentExecutor, create_tool_calling_agent
from langchain_core.prompts import ChatPromptTemplate
from forgein.integrations.langchain import ForgeinContextTool

tools = [ForgeinContextTool(project="my-saas-app")]
llm = ChatAnthropic(model="claude-opus-4-8")
prompt = ChatPromptTemplate.from_messages([
    ("system", "You are a helpful coding assistant."),
    ("human", "{input}"),
    ("placeholder", "{agent_scratchpad}"),
])
executor = AgentExecutor(
    agent=create_tool_calling_agent(llm, tools, prompt),
    tools=tools,
)
result = executor.invoke({"input": "What are the Drizzle ORM conventions in this project?"})

Requires pip install "forgein[langchain]".ForgeinContextTool is a standard LangChain BaseTool that reads memory on demand.

Client reference

ForgeinClient(
    token=None,        # defaults to FORGEIN_API_TOKEN env var
    *,
    base_url=None,     # defaults to FORGEIN_BASE_URL or https://api.forgein.ai
    timeout=30.0,      # seconds
    max_retries=3,     # applied to 429 and 5xx responses
)
AsyncForgeinClient(...)   # identical signature

Additional resources on the client:

AttributeDescription
client.adaptersFetch and sync context files across all AI tools
client.memoryCRUD + search + health for memory files
client.tokensList, create, and revoke API tokens
client.webhooksRegister endpoints, view deliveries, send test pings
client.authCurrent user info
client.contextsOrg context template management
client.sharesShareable context URL generation
client.referralsReferral invite management

Error handling

from forgein.exceptions import (
    ForgeinError,          # base class — exposes .status_code and .response
    AuthenticationError,   # 401
    PermissionDeniedError, # 403
    NotFoundError,         # 404
    RateLimitError,        # 429 — also exposes .retry_after: float | None
    ServerError,           # 5xx
    NetworkError,          # connection-level failures
)

try:
    context = client.adapters.get("copilot", project="my-saas-app")
except RateLimitError as e:
    time.sleep(e.retry_after or 5)
except AuthenticationError:
    raise SystemExit("Check FORGEIN_API_TOKEN")

The client retries 429 and 5xx responses automatically (up to max_retries times, respecting Retry-After headers). 4xx errors other than 429 are not retried.

CLI

Requires pip install "forgein[cli]".

forgein auth                                   # verify token
forgein health                                 # API status
forgein context get <project> [--adapter ...]  # print context to stdout
forgein context sync <project> [--path .]      # write context files
forgein memory list <project>                  # list memory files
forgein memory get <project> <path>            # read a file

Environment variables

VariableDefaultDescription
FORGEIN_API_TOKENAPI token (required)
FORGEIN_BASE_URLhttps://api.forgein.aiOverride API base URL

Testing

pip install "forgein[dev]"
pytest

Tests use respx to mock httpx at the transport level. No network access required.

← All docsPyPI ↗Report a bug ↗