forgein — sync context in any Python agent or LLM pipeline. Sync and async clients, Anthropic / OpenAI / LangChain integrations, 22/22 tests green.
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.
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.
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
| Method | Returns | Description |
|---|---|---|
| .get(adapter, *, project) | str | Fetch context string for one adapter |
| .sync(project, *, path=".", adapters=None) | SyncResult | Write context files to disk |
| .usage() | AdapterUsage | Per-adapter usage stats and 14-day sparkline |
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")| Method | Returns | Description |
|---|---|---|
| .list(project) | list[MemoryFileMeta] | List files without content |
| .get(project, path) | MemoryFile | Read a single file |
| .put(project, path, content) | MemoryFileMeta | Create or update a file |
| .delete(project, path) | None | Delete a file |
| .projects() | list[MemoryProject] | All projects with file counts |
| .search(query) | list[SearchResult] | Full-text search across all memory |
| .stats() | MemoryStats | Aggregate counts and byte sizes |
| .health() | MemoryHealth | Stale-context detection |
| .history(project, path) | list[MemoryHistoryEntry] | Version history (up to 50) |
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).
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=.
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.
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.
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 signatureAdditional resources on the client:
| Attribute | Description |
|---|---|
| client.adapters | Fetch and sync context files across all AI tools |
| client.memory | CRUD + search + health for memory files |
| client.tokens | List, create, and revoke API tokens |
| client.webhooks | Register endpoints, view deliveries, send test pings |
| client.auth | Current user info |
| client.contexts | Org context template management |
| client.shares | Shareable context URL generation |
| client.referrals | Referral invite management |
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.
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
| Variable | Default | Description |
|---|---|---|
| FORGEIN_API_TOKEN | — | API token (required) |
| FORGEIN_BASE_URL | https://api.forgein.ai | Override API base URL |
pip install "forgein[dev]" pytest
Tests use respx to mock httpx at the transport level. No network access required.