AgentForge is a personal AI agent runtime designed to run on an always-on Windows 11 PC and be controlled remotely through Telegram.
The current MVP focuses on the runtime foundations:
- Telegram Long Polling as the remote UI
- Antigravity CLI as the default LLM provider
- Codex Python SDK provider support
- OpenAI-compatible Local LLM provider support
- Plugin-style agents loaded through an agent registry
- Job, chain, worker, session, and logging foundations
- Telegram bot interface for submitting prompts and checking runtime status
- Background job queue with persisted job state
- Per-chat/user sessions for Telegram runtime state and default agent/provider selection
- Chain-based conversation context with one job per user turn
- Background job execution routed by job kind
- File-based storage for jobs, chains, sessions, logs, results, and legacy backups
- Pluggable agents and tools
- LLM provider abstraction for Codex, Antigravity CLI, and OpenAI-compatible endpoints
- Windows 11 or a compatible Windows environment
- Python 3.12+
- A Telegram bot token
- One configured LLM provider:
- an authenticated Codex SDK session
- an authenticated Antigravity CLI available as
agy - an OpenAI-compatible local LLM endpoint
python -m venv .venv
source .venv/Scripts/activate
pip install -e ".[dev]"
cp .env.example .envSet the Telegram token in your shell if you start the runtime directly:
export TELEGRAM_BOT_TOKEN="your-bot-token"If you start with ./script/run.sh, put the same variables in .env instead.
If you use the local provider, also set the local API key in your shell or .env:
export LOCAL_LLM_API_KEY="your-local-api-key"Start the runtime directly:
python -m agentforge.mainOr use the helper script, which loads .env before starting:
./script/run.shThe default configuration uses the Antigravity CLI provider. Make sure the CLI
is authenticated and can run non-interactively with agy -p "your prompt"
before starting AgentForge.
If you switch to the Codex provider, it uses openai-codex, which reuses an
existing Codex login session. If Codex is not already authenticated on the
machine, complete the Codex SDK login flow before starting AgentForge.
AgentForge reads config.yaml from the working directory.
The default provider is Antigravity:
llm:
default_provider: antigravityThe default configuration also includes:
telegram.bot_token_env: environment variable that contains the Telegram bot tokentelegram.polling_timeout_seconds: Telegram long polling timeoutllm.providers.codex: Codex model and sandbox settingsllm.providers.antigravity: Antigravity CLI command, model, and timeout settingsllm.providers.local: OpenAI-compatible local endpoint settingsagents.default_agent: active agent for new sessionsagents.enabled: agent modules to load fromagentforge.agentsstorage.*: directories for jobs, chains, sessions, logs, results, and backupsworker.polling_interval_seconds: background worker polling intervalsession.max_messages: maximum chain message history retained per chain
To use a local OpenAI-compatible endpoint, switch the default provider:
llm:
default_provider: localThen configure llm.providers.local.base_url, model, and api_key_env.
To use Codex, switch the default provider:
llm:
default_provider: codexThen configure llm.providers.codex:
llm:
providers:
codex:
model: gpt-5.4
sandbox: read_onlyThe Codex sandbox can be read_only, workspace_write, or full_access.
The Antigravity command value can be changed if the CLI is installed under a
different name or absolute path.
AgentForge separates execution records from conversation context:
Job: one execution attempt. A normal Telegram message creates oneconversationjob.Chain: conversation context. It stores messages and references the jobs created inside that context.Session: Telegram chat/user runtime state. It stores default agent/provider selections and the active/default chain ids.JobExecutor: routes jobs by kind. Conversation jobs callAgentRuntime; workflow jobs are reserved for future service workflows.
New sessions always get a default chain. Regular chat messages use that default chain unless the user starts or switches to an explicit chain.
After the bot is running, send messages to the Telegram bot.
/start: check that AgentForge is running and point to/help/help: list available commands/agents: list registered agents/use <agent_id>: change the active agent for the current session/providers: list configured LLM providers/provider [provider_id]: show or change the active LLM provider/jobs: list recent jobs/job <job_id>: show one job's status and result summary/logs <job_id>: show recent log lines for a job/result <job_id>: resend a job result, including a file if one exists/chain start [name]: create a new explicit chain and switch to it/chain status: inspect the active chain/chain list: list chains for the current session/chain switch <chain_id | name>: switch the active chain/chain end: complete the active explicit chain and return to the default chain/chain cancel: cancel the active explicit chain and return to the default chain
Any non-command text is accepted as a new conversation job for the active chain. When a job finishes, the worker sends the result back to the same Telegram chat.
When the default chain is active, /use and /provider update the session
defaults and the default chain. When an explicit chain is active, they update
only that chain.
TelegramPollingBotreceives updates through Telegram Long Polling.TelegramUpdateMapperconverts text messages into inbound runtime messages.MessageRoutersends commands toCommandHandlerand normal prompts toConversationHandler.ConversationHandlercreates apreparingconversation job for the active chain.ChainServicestores the user message and links the job id to the chain.JobServicemarks the jobpendingafter the chain update succeeds.BackgroundWorkerpicks up pending jobs and passes them toJobExecutor.JobExecutorroutes the job byjob.kind.ConversationExecutorloads chain history and callsAgentRuntime.AgentRuntimebuilds an agent prompt and calls the configured LLM provider.ChainServicestores the assistant response with the same job id.TelegramResponseSendersends the final result back to Telegram.
Agents are loaded from modules under agentforge.agents.
For each enabled agent id in config.yaml, the loader imports:
agentforge.agents.<agent_id>
That module must expose create_agent(config). The returned agent should provide:
metadata: id, name, description, and allowed tool namesget_tools(): tools exposed by the agent during the compatibility phasebuild_prompt(context): converts runtime context into an LLM requesthandle_response(response, context): converts the provider response into an agent result
The included demo agent summarizes host PC status using simple system tools.
By default, runtime data is stored under data/:
data/jobs: one execution record per jobdata/chains: conversation contexts and chain messagesdata/sessions: Telegram chat/user runtime statedata/logs: job and conversation logsdata/results: reserved for generated result filesdata/backups: legacy runtime data moved aside during schema changes
These paths can be changed in config.yaml.
Run tests with:
pytestThe package also installs a console script:
agentforge