@context is a self-hosted context manager. It organizes your work context into a private CRM and knowledge base and helps you stay on top of things.
It plugs into clients like claude, chatGPT, claude code, and codex, and gives them a single source of @context about your work. I use it with claude code to manage product specs.
Your AI tools are users of context, not competitors.
@context is built with privacy and security as first principles. It runs in two modes:
- Owner mode. You get every tool. Capture context ("met Kyle from Agno, follow up next week"), retrieve context ("give me a rundown of my day"), and prepare context ("process today").
- Guest mode. Teammates (and their agents) can leave updates in your queue, check whether you've seen their own updates, and — when your calendar is connected — ask for your open windows (free/busy only, never event details) to request time with you. You get briefed when you ask for a rundown, and when you acknowledge an update the sender gets a one-line "seen" receipt.
@context runs on Agno's AgentOS runtime, so user identity is verified on every request, and tools are assigned by role (owner or guest).
Built on Agno.
@context has five jobs.
-
Maintain a CRM. Share "met Kyle from Agno, wants a partnership, follow up next week", and it stores a contact, a note, and a dated reminder without you picking forms or fields.
-
Maintain a knowledge base. @context writes product specs, parses customer interview notes, manages project briefs, and runs deep research, then keeps it all neatly organized in one place.
-
Run your day, plan your week, prep ahead. @context runs repeatable playbooks to make things easier. A few come built in, and you should customize them and add your own. Here are the included ones:
- Rundown ("what's on today?"): a prioritized brief of things on your plate. One digest instead of five apps: the updates teammates (and their agents) left in your queue, reminders that are due, today's meetings, the emails you missed, and the Slack threads worth a look.
- Week plan ("what's my week?"): priorities for the week. Runs Sunday evening and lands in your DMs, so you start the week with 🔥
- Prep ("prep for my 2pm with Kyle"): a tight pre-meeting brief covering who they are, notes, past threads, what's still open, email and Slack exchanges, and public background from the web for contacts you don't know yet.
@context runs these playbooks on demand or on a schedule. The daily rundown and weekly plan DM the brief straight to you.
-
Represent you. Your teammates (and their agents) can share non-urgent updates with your @context. A teammate types "@your-context my claude fixed the auth bug", and it lands in your queue and surfaces in your next rundown. It works outbound too. Your @context can message people and channels on Slack on your behalf, and @-mention a teammate's @context to drop an update in their queue. That's how a team's contexts talk to each other (the context network). This keeps your signal-to-noise high.
-
Draft and schedule. Connect Gmail and Calendar, and @context reads your real inbox and calendar, drafts your follow-ups straight into Gmail for you to send, and sends calendar changes to your approvals queue.
@context is an alter ego with access to a lot of sensitive information, so the security boundaries need to be AIRTIGHT.
Agno's AgentOS makes two things possible:
- Verify the user making the request. AgentOS extracts the
user_idfrom the JWT or the Slack request, so we can tell whether the caller is the owner or a guest. - Assign tools by role. Based on that, we add the right tools to the agent.
This model lets us build a system that anyone can write to, but only you can read from or act through. To everyone else, it is a polite notetaker that only captures. Although it does remember who it is talking to: each caller gets their own user-memory, kept entirely separate from yours.
External actions are double gated. Changing your calendar (update_calendar) pauses for explicit approval before it runs, using AgentOS's requires_confirmation and approval_type="required" settings. Email goes a step further. update_gmail can only draft, so the follow-up waits in your Gmail drafts for you to review and send. It never sends on its own.
Everything runs locally or in your own cloud, inside your VPC. Every byte of data lives in your own database: the CRM, the knowledge base, and the inbox.
Read docs/SECURITY.md for more details.
Requires Docker installed and running.
git clone https://github.com/agno-agi/context.git
cd context
# Configure credentials
cp example.env .env
# Open .env: set OPENAI_API_KEY, and set OWNER_ID to the email you sign in to os.agno.com with.
# OWNER_NAME is an optional display name, set it as your name.
# Run on Docker
docker compose up -d --buildConfirm it is live at http://localhost:8000/docs.
@context runs on AgentOS, which comes with a web UI for managing and monitoring @context. Use the AgentOS UI to chat with @context, view sessions, approve actions and more.
- Open os.agno.com and sign in with your email (the same one you set as
OWNER_ID). - Click Connect AgentOS → Local.
- Enter
http://localhost:8000, name it "Local Context" and connect. - Click on the chat button under Context.
- Try one of the quick prompts.
The main way to use @context is from an MCP client like Claude Code, Codex, Claude, Cursor, and ChatGPT. Connect your favorite AI tools to @context's MCP server at http://localhost:8000/mcp.
Note: @context's MCP server is owner-only, so keep an eye on security.
Add @context to every MCP client on your machine with one command:
python scripts/connect.pyThe script finds Claude Code, Codex, the Claude Desktop app, and Cursor, and registers @context with each. Use --dry-run to preview and --remove to undo. It wires the local dev server; a deployed instance uses OAuth instead — see Connect production @context MCP server.
For CLI clients, run the following commands:
claude mcp add -s user --transport http context http://localhost:8000/mcp # Claude Code (user scope)
codex mcp add --url http://localhost:8000/mcp context # CodexClaude Desktop needs that bridge in claude_desktop_config.json, because its "Add custom connector" dialog only accepts https URLs. Add this (keep any existing keys) and restart the app:
{
"mcpServers": {
"context": {
"command": "npx",
"args": ["-y", "mcp-remote", "http://localhost:8000/mcp", "--transport", "http-only"]
}
}
}Cursor speaks remote MCP directly (no bridge). Add this to ~/.cursor/mcp.json and restart Cursor:
{
"mcpServers": {
"context": {
"url": "http://localhost:8000/mcp"
}
}
}See docs/MCP.md for more details.
Slack is where @context comes alive. It's the interface where I (@ashpreetbedi) use it the most and the interface that allows your team (and their agents) to talk to @context.
To set it up, you need to:
- Create a Slack app
- Get the Bot User OAuth Token and Signing Secret
- Set the environment variables in
.envor.env.production - Restart the application
Read docs/SLACK.md for the Slack setup guide.
@context comes with a knowledge base that acts as its second brain. @context stores everything from product specs and research notes to "what I know about X" pages in this knowledge base.
The knowledge base is stored on the filesystem by default (a gitignored knowledge/ folder in this repo) but I highly recommend pointing it to a git repo or notion database for production. See docs/KNOWLEDGE.md for the full guide.
Try:
- Write a one-pager on the advantages of building our own agent-platform
- Write up a decision: we're standardizing on agno
- What in my knowledge base needs attention?
@context comes with a CRM that gives it structured memory about people, projects, meetings, reminders, notes and contacts.
This auto-managing crm is @context's superpower. Use it to manage projects, meetings, reminders, notes, and contacts. @context maps what you tell it onto the right table - no forms, no fields - and can create new tables on demand. Try:
- "Add Dana Reyes, Head of Platform at Acme, dana@acme.com - and remind me to send her the integration spec next Tuesday."
- "Who do I know at Acme?"
- "What reminders do I have coming up?"
- "Tell me about Northwind."
@context's database lives in the crm Postgres schema: writes are confined to that schema and every row is scoped to your user_id, so a guest can't see this data. See docs/CRM.md for the schema, the filing rules, and the write boundary.
@context runs anywhere that runs a Docker container.
For a quick deployment, the repo includes a script to run on Railway. The scripts/railway/up.sh script will run @context as a service with Postgres on the same private network. It reads credentials from .env.production, and creates a public domain you connect to in the AgentOS UI.
Requires the Railway CLI
Create the production environment file.
cp .env .env.productionThe deploy scripts read .env.production first and fall back to .env if it doesn't exist.
Run the up.sh script to run @context + postgres on Railway.
First, login to Railway.
railway loginThen run the up.sh script.
./scripts/railway/up.shThe script will now pause and wait for you to mint the JWT verification key.
Token-Based Authorization is on by default. Without the JWT_VERIFICATION_KEY environment variable in .env.production, the AgentOS will not serve traffic. That is the safe default for an agent that has access to sensitive information. You can issue and verify your own JWT (see BYO JWT) or mint a JWT verification key at os.agno.com.
The up.sh script pauses and waits for you to add the JWT verification key to .env.production. Here's how you can get one from os.agno.com:
- Open os.agno.com, click Connect AgentOS → Live
- The
up.shscript will print the AgentOS domain, paste it into the input field. - Enable Token Based Authorization and click Connect.
- Copy the public key and paste it into
.env.production. - Back in the terminal, press Enter.
up.shwill read the key and deploy the AgentOS service to Railway.
You can verify the deployment on the Railway dashboard or in the terminal by watching the logs:
railway logs --service agent-osIf you add/update any values in .env.production, you can sync them to Railway with:
./scripts/railway/env-sync.shIf you make code changes (which you most definitely will), you can redeploy the AgentOS service to Railway with:
./scripts/railway/redeploy.shOr enable auto-deploy in the Railway dashboard:
- Open the Railway dashboard
- Navigate to the agent-os service
- Click Settings
- Click Source and select the git repo for this project
- Set the deploy branch to
mainand click Deploy
If you set Slack up locally, your Slack app's request URLs still point at your local @context via the ngrok tunnel.
Repoint the /slack/events and /slack/interactions request URLs to your Railway domain. AgentOS must already be deployed and serving traffic so Slack's URL re-verification passes.
See docs/SLACK.md for full steps.
Once @context is deployed (you have a Railway domain), MCP clients connect over OAuth — no tokens to mint, nothing to paste into client configs. Setting MCP_CONNECT_SECRET turns the deployment into its own OAuth 2.1 authorization server on /mcp: a client connects by URL, and you approve it once on a consent page by typing the secret.
./scripts/railway/up.sh already generated the secret for you. If you deployed before it existed (or want to double-check), one command arms everything:
./scripts/setup_context.sh # ensure the secrets → sync env → redeploy → print the connector recipescripts/setup_context.sh checks railway login, makes sure MCP_CONNECT_SECRET and AGENTOS_MCP_SIGNING_KEY exist in .env.production (generating them when missing), syncs the env to Railway, runs a railway up redeploy (so a railway.json change like numReplicas lands), then prints the connector recipe below with your real domain and secret. Add --no-redeploy to skip the redeploy. It never restarts apps for you or touches your data.
Then connect your clients:
- claude.ai / ChatGPT (web): add
https://<your-domain>/mcpas a custom connector. Leave the OAuth client ID/secret fields empty — the server registers the client dynamically. Click Connect and approve the consent page with yourMCP_CONNECT_SECRET. - CLI clients:
uvx agno connect --url https://<your-domain>wires Claude Code, Codex, Cursor, and Claude Desktop and prints each client's sign-in step. Or by hand:claude mcp add --transport http context https://<your-domain>/mcp, thenclaude mcp login context(a browser consent) —codex mcp add/codex mcp loginfor Codex.
The AgentOS UI keeps working alongside — it authenticates with the os.agno.com JWT, a separate door from MCP OAuth. If a client ever needs to be cut off, rotating AGENTOS_MCP_SIGNING_KEY revokes every issued token at once (every client re-consents); rotating MCP_CONNECT_SECRET only gates future consents.
See docs/MCP.md for the full details: the consent flow, per-client specifics, ChatGPT/Claude web, and how it's secured.
When testing locally we can use the local knowledge/ folder to store the knowledge base. But in production we need to back the knowledge base with a durable solution like a Git repo.
Here's how to connect @context's knowledge base to a Git repo.
- Open github.com/new and create a new repo for your @context's knowledge base.
- Name:
your-username/your-context - Visibility: Mark the repo as private.
- Add README: Yes
- Name:
- Mint a GitHub token with push access to the repo.
- Open github.com/settings/personal-access-tokens and create a new fine-grained token.
- Click on Generate new token
- Name:
Your Context - Expiration: No expiration
- Repository access: Only select repositories and select the repo you created in step 1.
- Add Permissions -> Select Contents
- Remember to update Access to read and write
- Generate token and copy the token.
- Add both to
.env.production:KNOWLEDGE_REPO_URL=https://github.com/you/your-specs.git KNOWLEDGE_GITHUB_TOKEN=ghp_...
- Sync to Railway:
./scripts/railway/env-sync.sh
See docs/KNOWLEDGE.md for the full guide.
You can connect your Gmail and Calendar to @context to ground the rundown and meeting prep in your real inbox and calendar.
See docs/GOOGLE.md for more details.
@context has three main components. Review them in order.
@context is a FastAPI application running the AgentOS runtime. app/main.py is the entrypoint and app/settings.py holds shared settings. app/identity.py is where identity is validated. It looks dense, but all it does is check whether user_id is in the OWNER_ID list (comma-separated). app/mcp.py is the owner-only MCP server — one tool (use_context) that lets you read, act, and file through @context from the Claude/ChatGPT desktop apps and CLI clients (see MCP server).
The main agent is agents/context.py. context_tools() adds tools to the agent based on the caller's role, and caller_information() adds the matching instructions.
The supporting files:
agents/instructions.pydefines the role-specific instructions.agents/sources.pydefines the context providers (crm, knowledge, workspace, web, Slack, Gmail, Calendar) and how each registers itsquery_/update_tools.agents/inbox.pydefines the inbound queue:submit_update(anyone), thenrundown/acknowledge(you only).agents/policy.pydefines the pre-hook and tool-hook that back the owner/guest boundary.workflows/defines the runnableWorkflowobjects (the reminder sweep, the digests) anddm_owner;app/schedules.pyregisters their crons. The reminder sweep (workflows/reminders.py) files due reminders into the inbound queue, run hourly by thequeue-remindersschedule.
The repo has two distinct kinds of skill. Keep them separate.
- Runtime skills (
skills/) are playbooks the deployed @context agent runs for its owner, invoked in natural language ("plan my week") and owner-gated. Add your own as needed. - Coding-agent workflows (
.agents/skills/) are/slash-commandworkflows your coding agent (Claude Code, Codex, others) runs while developing this repo. They are covered under Working with coding agents.
Here are the runtime skills that are included in the repo:
skills/week-plan/SKILL.md.skills/daily-rundown/SKILL.md.skills/prep-for/SKILL.md.skills/process-today/SKILL.md.skills/research/SKILL.md.skills/knowledge-review/SKILL.md.
@context comes with an eval suite (evals/) for regression testing. It tests the claim that: anyone can write, only you can read.
Run it:
python -m evals # run the full suite
python -m evals -v # stream the full agent run
python -m evals --case <name> # one case| Variable | Required | Default | Description |
|---|---|---|---|
OPENAI_API_KEY |
yes | none | OpenAI key for models and embeddings. |
OWNER_ID |
prd | none | Comma-separated identities that count as the owner (JWT sub and/or Slack email). First is canonical. Unset means capture-only for everyone. |
OWNER_NAME |
no | canonical OWNER_ID |
Display name rendered into the prompt. Cosmetic, never matched as an identity. |
OWNER_TIMEZONE |
no | UTC |
Your IANA timezone (e.g. America/Los_Angeles). Anchors "today", due/overdue math, and relative dates to your local day. |
RUNTIME_ENV |
no | prd |
dev enables hot-reload and disables JWT. Compose sets this to dev for local. |
JWT_VERIFICATION_KEY |
prd | none | Public key from os.agno.com. Required when RUNTIME_ENV=prd. |
MCP_CONNECT_SECRET |
no | none | Arms MCP OAuth: the deployment becomes its own OAuth 2.1 authorization server on /mcp, and clients (claude.ai, ChatGPT, Claude Code, Codex, Cursor) connect by URL — you approve each one on a consent page by typing this secret. At least 16 chars (openssl rand -base64 32); scripts/railway/up.sh generates one. Unset means no OAuth (local dev stays keyless). See Connect production @context MCP server. |
AGENTOS_MCP_SIGNING_KEY |
no | generated, kept in Postgres | Pins the HS256 signing root for the MCP OAuth tokens (at least 32 chars). Pin it in production; rotating it revokes every issued token (the kill switch) — rotating MCP_CONNECT_SECRET only gates future consents. |
AGENTOS_URL |
no | http://127.0.0.1:8000 |
Scheduler base URL. Also anchors the MCP server's Host allowlist — set it to your Railway/ngrok domain so the deployed or tunnelled /mcp endpoint accepts that Host (see docs/MCP.md). |
INTERNAL_SERVICE_TOKEN |
no | auto-generated | Scheduler-to-OS auth token. The deploy ships 1 replica, so the auto-generated value is fine; scripts/railway/up.sh still pins one so scaling up stays correct (override in .env.production). See docs/SCALING.md. |
PARALLEL_API_KEY |
no | none | Switches the web source from keyless Parallel MCP to the authenticated SDK (higher rate ceiling); recommended for production. Get a key at platform.parallel.ai. |
SLACK_BOT_TOKEN / SLACK_SIGNING_SECRET |
no | none | Both enable the Slack interface. The bot token alone activates the slack source (query_slack + the ungated update_slack send tool) and auto-arms the scheduled digests. See docs/SLACK.md. |
SLACK_USER_TOKEN |
no | none | A Slack user token (xoxp-, scope search:read). Unlocks workspace-wide message search for query_slack; without it reads fall back to channel/thread history. |
DAILY_DIGEST_CRON / WEEKLY_DIGEST_CRON |
no | 0 13 * * * / 0 22 * * 0 |
UTC cron for the Slack-delivered daily rundown and weekly plan (only armed when Slack is set). See docs/SLACK.md. |
GOOGLE_CLIENT_ID / GOOGLE_CLIENT_SECRET / GOOGLE_PROJECT_ID |
no | none | Connect your Gmail + Calendar; mint tokens with python scripts/google_mint_tokens.py. See docs/GOOGLE.md. |
GMAIL_TOKEN_JSON_B64 / CALENDAR_TOKEN_JSON_B64 |
no | none | Minted Gmail/Calendar tokens as base64, so they survive a deploy. The entrypoint restores them at startup. See docs/GOOGLE.md. |
GMAIL_TOKEN_FILE / CALENDAR_TOKEN_FILE |
no | <repo>/gmail_token.json, <repo>/calendar_token.json |
Where the Google OAuth token caches live (read by the providers, written by the mint script). |
USE_CONTEXT_TIMEOUT |
no | 55 |
Hard ceiling (seconds) for one use_context MCP run — keep it under the client's own tool timeout. |
PROVIDER_TIMEOUT / BACKBONE_TIMEOUT |
no | 20 / 35 |
Per-source ceilings (seconds) for best-effort and backbone (CRM) reads in a rundown's fan-out. |
THREAD_POOL_WORKERS |
no | 64 |
Size of the thread pool that runs sync provider I/O — the stock ~6 queues fast sources behind slow ones. |
KNOWLEDGE_REPO_URL / KNOWLEDGE_GITHUB_TOKEN |
no | none | Set both to back the knowledge base with a Git repo instead of local files. Optional knobs: KNOWLEDGE_BRANCH (default main), KNOWLEDGE_LOCAL_PATH. |
DB_HOST / DB_PORT / DB_USER / DB_PASS / DB_DATABASE |
no | matches compose | Postgres connection. |
DB_DRIVER |
no | postgresql+psycopg |
SQLAlchemy driver. |
AGNO_DEBUG |
no | False |
If True, Agno emits verbose debug logs. Compose sets this for dev. |
WAIT_FOR_DB |
no | False |
If True, the entrypoint blocks on the DB before starting. Compose sets this. |
AGENTS.md: architecture and conventions (source of truth for coding agents).- Agno documentation
- AgentOS introduction
- Agno on GitHub (drop a star if this is useful).