Created by Vulkgryph LLC.
An autonomous AI coding agent that runs locally against OpenAI-compatible, Anthropic, or ChatGPT Codex endpoints. Forge reads, writes, and executes code in your project — driven by forge-tui-rs (the terminal UI) or forge-ide (a full code editor), both talking to this binary over the same headless JSON protocol. See the top-level README for how the three fit together.
Forge is built for engineers who want a tool they can rely on, not a tool they chase. The aim is a small, readable codebase with a stable interface — so the command you learn today behaves the same way the next time you use it, and your config file doesn't need to be rewritten between releases.
Versioning and compatibility:
- Every release is built to be as backwards-compatible as possible. Commands, config keys, file formats, and the headless JSON protocol stay valid across minor versions by default.
- Major versions are reserved for changes that genuinely need a break. When one ships, it includes a clear explanation of why the change was required and what it affects, plus either a straightforward manual migration or automatic migration.
- Deprecations are flagged in advance. Nothing that worked in the last release gets removed in a surprise patch.
While Forge is in the pre-1.0 phase, SemVer's 0.y.z exception applies: breaking changes may ship within minor or patch versions when correctness requires it (for example, removing a feature that conflicts with an upstream provider's terms). The full commitments above lock in at v1.0.0.
Forge is intentionally not chasing the newest agent architecture every month. If you want a tool that ships a new "workflow paradigm" every release, Forge is probably not for you. If you want a tool whose interfaces stay stable while the implementation gets smaller, faster, and more reliable underneath, that's what Forge is trying to be.
Inspection is the point. The source is here. The architecture is documented in ARCHITECTURE.md. The public roadmap lives at vulkgryph.com/roadmap. Read it, verify it, disagree with it. If something looks wrong, file an issue or email contact@vulkgryph.com. If you want to take it a different direction, fork it.
On limitations. Catching every edge case after a patch is beyond what testing alone can cover. After an update we know roughly what changed; the community is what surfaces the edge cases and unexpected behavior that a release notes line can miss. If a patch breaks something for you — a workflow that worked before, an integration that no longer behaves the same, a config that stopped being honored — file an issue. Even a one-line report helps — knowing something changed for someone is what testing can't replicate.
- Fully offline-capable — runs with no internet when paired with a local LLM (LM Studio, Ollama, llama.cpp, vLLM, etc.). See Offline use below.
- Full coding toolkit — read/write files, apply unified diffs, search code, run shell commands, fetch a URL (
web_fetch).web_searchships disabled and does not work in practice — see Web search does not really work - Parallel subagents — delegate subtasks to specialized agents running concurrently
- Planning mode — agent drafts a plan for your approval before making changes
- Session persistence — resume prior sessions with full context
- Context compaction — LLM-backed summarization keeps long sessions healthy
- Rolling window context — optionally drop oldest messages instead of compacting
- Configurable tool access — disable selected tools from the UI/settings
Forge is a sharp tool: powerful, useful, and dangerous if mishandled.
Forge does not provide practical isolation from the host machine. Its safety mechanism is approval-based command gating: it asks before write and execute tools unless you enable auto-approval modes or --dangerously-allow-all. Once a tool is approved, Forge runs with the same filesystem, shell, network, credential, and process access as the user account that launched it.
The project root is the default working directory, not a sandbox. File tools and shell commands can access paths outside the project when the underlying operating system permissions allow it. Use Forge only in workspaces and user accounts where that level of access is acceptable, review commands before approving them, and treat auto-approval modes as trusted-session features.
Launching forge --dangerously-allow-all requires an interactive confirmation. The flag is exactly what it says — every tool approval gate is bypassed for the whole session — so Forge prints what that means and asks you to type yes before it starts the agent. Anything else, including an empty line, exits. Set FORGE_SKIP_DANGEROUS_CONFIRM=1 for scripted / CI use where the operator has already accepted the risk.
The gate belongs to the forge command, which is the entry point a person types. forge-agent --headless is a protocol server driven by a UI and owns no terminal to ask on, so it takes the flag as given — the UI in front of it is where the asking happens, and the editor confirms before it will switch a tab into Skip All Permissions.
- A watcher started in the background can fail without saying so. Long-running
processes launched with
run_in_background=true— file watchers, dev servers, anything that is meant to stay up — have been observed dying or never starting while the agent goes on as though they were running. Nothing surfaces in the tool result, so the first sign is that the thing you expected to be watching never reports anything. If you depend on a watcher, verify it yourself (background_actionto poll it, or check the process) rather than trusting that the call succeeded. Root cause is not yet established.
Forge runs with no internet when paired with a local LLM. Useful for airgapped environments, secure facilities, weak connections, or anyone who simply doesn't want their code shipped to a cloud provider.
What requires network:
| Component | When it talks to the network |
|---|---|
| LLM endpoint | Always — but if it's local (127.0.0.1:1234, etc.) that traffic stays on your machine |
web_search / web_fetch tools |
Only when the model invokes them. Disable both via agent.disabled_tools = ["web_search", "web_fetch"] if you want them off the table |
| Codex subscription auth | Only on login + periodic token refresh, only if you're using the ChatGPT Codex provider |
| Codex version self-check | Background, once a week, only if you're actively using Codex; if GitHub is unreachable forge falls back to a cached value |
Minimum offline setup:
- Local LLM running (LM Studio / Ollama / llama.cpp / vLLM)
- Wizard option 1 (Local LLM server) when running
install.sh - Disable network tools in
~/.config/forge/config.toml:[agent] disabled_tools = ["web_search", "web_fetch"]
- Set
FORGE_NO_AUTO_VERSION_CHECK=1to suppress the once-a-week GitHub poll Forge uses to keep its Codexclient_versioncurrent (only relevant if you'd ever use the ChatGPT Codex provider anyway):export FORGE_NO_AUTO_VERSION_CHECK=1
Simplest route, instead of the four steps above: set offline_mode = true under
[agent], or toggle it from the tools menu. It forces off the web tools, the
weekly version self-check, and the Codex model-catalog fetch in one move.
After that, Forge has zero outgoing network traffic outside your local LLM.
One detail about the requests Forge does make: they carry an x-forge-session
header, so a provider's logs can group one conversation's requests together
(subagents get the same id with a suffix). It is the local session id —
YYYYMMDD_HHMMSS_ plus three hex characters, a timestamp rather than anything
about you — it goes only to the endpoint you configured, and it reports nothing
back here. Forge collects no telemetry of any kind.
Forge respects a small set of environment variables for users who want to override defaults. None are required.
| Variable | Effect |
|---|---|
FORGE_NO_AUTO_VERSION_CHECK=1 |
Skip the weekly GitHub poll that keeps the Codex client_version string current. Cached values are still used; a hardcoded baseline applies if the cache is empty. |
FORGE_SHOW_INTERNAL_MODELS=1 |
Show ChatGPT Codex models marked as internal (e.g. codex-auto-review). These aren't general chat targets — selecting one will likely fail at the API. Hidden by default. |
FORGE_SKIP_DANGEROUS_CONFIRM=1 |
Skip the confirmation prompt that fires when launching with --dangerously-allow-all. Intended for scripted / CI usage; never set in interactive shells. |
FORGE_AGENT_PATH |
Override the path the wrapper uses to find forge-agent. Useful for testing local builds. |
FORGE_RUSTUP_SHA256 |
Pin the expected SHA-256 of the rustup installer when install.sh fetches it. If unset, the script prints the hash so you can pin it on a future run. |
FORGE_REPO / FORGE_DEST / FORGE_BRANCH |
Override defaults in bootstrap.sh / bootstrap.ps1. |
Developed and used on macOS (Apple Silicon). On Linux the two architectures have different evidence behind them, and neither has been used interactively:
- x86-64 — CI builds it and the tests pass on every push. Nobody has run it on a Linux desktop.
- ARM64 — genuinely exercised, but only headless: remote development uploads this binary to an aarch64 machine and drives it over SSH, with no terminal of its own. Nothing on that architecture goes through CI.
Windows and Intel Macs are untested. See the platform table.
- macOS, Linux, or Windows
- Rust (installed automatically by the installer if missing)
- An LLM endpoint — OpenAI-compatible, Anthropic, or ChatGPT Codex
Linux preflight — on a minimal Ubuntu/Debian image you may need to install a C toolchain and unzip before running install.sh:
sudo apt-get update && sudo apt-get install -y git build-essential unzipinstall.sh will detect these and tell you exactly what to install if any are missing.
Windows preflight — install.ps1 uses winget to install missing prerequisites (Git, and Rust via rustup). It assumes Visual Studio Build Tools 2022 (or higher) is already installed for the MSVC linker — install from aka.ms/vs/17/release/vs_BuildTools.exe with the "Desktop development with C++" workload if missing.
curl -fsSL https://raw.githubusercontent.com/Vulkgryph/Forge/main/bootstrap.sh | bashIn PowerShell:
irm https://raw.githubusercontent.com/Vulkgryph/Forge/main/bootstrap.ps1 | iexBoth bootstrap scripts handle the preflight, clone the repo to ~/forge (or $env:USERPROFILE\forge on Windows), and run the appropriate installer.
Override defaults via environment variables:
FORGE_DEST— clone destination (default:~/forgeor$env:USERPROFILE\forge)FORGE_BRANCH— branch to check out (default:main)FORGE_REPO— alternative repo URL
macOS / Linux:
git clone https://github.com/Vulkgryph/Forge.git forge
cd forge
./install.shWindows (PowerShell):
git clone https://github.com/Vulkgryph/Forge.git forge
cd forge
.\install.ps1The installer's first question is how you want Forge to reach an LLM:
1) Local LLM server (LM Studio, Ollama, llama.cpp, vLLM, etc.)
2) Claude (Anthropic API key — subscription OAuth login is not supported)
3) ChatGPT Codex subscription (OAuth login)
4) Direct API key (Anthropic, OpenAI, OpenRouter, custom OpenAI-compatible)
5) Skip — I'll edit the config file myself
- Local (1): you'll be asked for the base URL, model ID, and context window. No defaults — paste whatever your server uses.
- Claude (2): you'll paste an Anthropic API key and pick a model. Claude Pro/Max subscription login is not supported — Anthropic's terms restrict subscription credentials to its own apps (see CHANGELOG).
- ChatGPT Codex subscription (3): writes a minimal config and offers to run the OAuth login inline. On a local machine, just say yes and a browser opens. On a remote VM over SSH, the installer detects this and tells you to first re-connect with port forwarding so the OAuth callback can reach the listener on the remote host:
- ChatGPT Codex OAuth uses port 1455:
ssh -L 1455:localhost:1455 <user>@<host>
- ChatGPT Codex OAuth uses port 1455:
- Direct API key (4): you'll pick a provider, paste your key, choose a model. The key is stored in
~/.config/forge/config.toml(so file permissions matter —chmod 600it if you're paranoid). - Skip (5): writes a placeholder config you can edit by hand at
~/.config/forge/config.toml. The file is annotated with examples for every endpoint type. Re-run./install.shlater if you want the interactive wizard.
When the wizard finishes:
forgePrefer to configure manually? See Configuration below.
From an installed checkout:
forge-updateOr from the repo:
./update.shThe updater uses git pull --ff-only, rebuilds forge-agent and the UI, reinstalls the local wrappers, and preserves your config in ~/.config/forge. If you have local source changes, it skips pulling and rebuilds the current checkout. Use ./update.sh --no-pull to rebuild/reinstall without touching git.
Config file: ~/.config/forge/config.toml
[models]
default = "local"
[[models.endpoints]]
name = "local"
base_url = "http://127.0.0.1:1234/v1"
model_id = "your-model-id"
max_context_tokens = 32768
max_output_tokens = 8192
[agent]
auto_approve_reads = true
auto_approve_writes = false
permission_mode = "default"
disabled_tools = []
context_strategy = "compaction"
max_history_messages = 200
compaction_threshold = 150
[agent.subagents]
enabled = true
max_depth = 4
max_concurrent = 4
default_model = "local"[models]
default = "main"
web_tool_model = "fast" # optional: smaller model for web_fetch summarization
[[models.endpoints]]
name = "main"
base_url = "http://127.0.0.1:8081/v1"
model_id = "Qwen3-Coder-80B"
max_context_tokens = 131072
max_output_tokens = 16384
[[models.endpoints]]
name = "fast"
base_url = "http://127.0.0.1:1234/v1"
model_id = "Qwen3-Coder-30B"
max_context_tokens = 65536
max_output_tokens = 8192
[agent]
auto_approve_reads = true
auto_approve_writes = false
disabled_tools = []
context_strategy = "compaction" # or "rolling_window"
[agent.subagents]
enabled = true
max_depth = 4
max_concurrent = 4
default_model = "fast"Forge can use your existing ChatGPT Codex subscription via OAuth — no API key purchase required:
From the command line:
forge --login chatgpt # OAuth for ChatGPT Codex
forge --login-chatgpt # shortcut form
# Lower-level equivalent (skip the wrapper):
forge-agent --login-chatgptOr from inside the TUI:
/login --chatgpt
After login, Forge stores OAuth credentials at ~/.config/forge/chatgpt_auth.json and adds the corresponding endpoint to your config.
Remote / firewall users: the OAuth flow listens on
localhost:1455(ChatGPT Codex). If your browser can't reach it (SSH session without port forwarding, corporate firewall, etc.), forge prints both the URL to visit AND a prompt to paste the callback code. After approving in your browser, the redirect page will fail to load — just copy the URL from your browser's address bar after it fails to load, and paste it into forge.
Claude (Anthropic): subscription (Pro/Max) login via Forge is not supported — there is no Claude OAuth code path in Forge, and
forge --login claudeexits with an error. Anthropic's terms restrict subscription OAuth credentials to its own applications and prohibit routing requests through Pro/Max credentials in third-party tools, so we don't. Use an Anthropic API key instead — add it to anendpoint_type = "anthropic"endpoint in~/.config/forge/config.toml(or pick Claude in the installer wizard). See the CHANGELOG for details.
| Key | Default | Description |
|---|---|---|
models.default |
— | Endpoint name used for the main agent |
models.web_tool_model |
same as default | Endpoint for web_fetch summarization |
agent.auto_approve_reads |
true |
Skip approval prompts for read-only tools |
agent.auto_approve_writes |
false |
Skip approval prompts for file writes |
agent.permission_mode |
"default" |
Stored permission preference. Related approval behavior is surfaced through multiple mechanisms: the TUI mode selector (normal / auto_accept / plan), per-session “approve always” tool memory, and the startup flag --dangerously-allow-all. The serialized enum supports default, accept_edits, bypass_permissions, dont_ask, plan |
agent.disabled_tools |
[] |
Tool names to exclude from normal turns |
agent.context_strategy |
"compaction" |
"compaction" or "rolling_window" |
agent.max_history_messages |
200 |
Hard cap on conversation history length |
agent.compaction_threshold |
150 |
Message count that triggers context compaction |
agent.subagents.enabled |
true |
Enable/disable parallel subagents |
agent.subagents.max_concurrent |
4 |
Max subagents running at once (1, 2, or 4) |
agent.subagents.max_depth |
4 |
Max subagent nesting depth |
agent.subagents.default_model |
same as default | Model endpoint subagents use |
forge [--cwd <path>]
forge-agent --headless [--resume-session <id>] [--dangerously-allow-all]forge launches the terminal UI wrapper (see ../forge-tui-rs/ for its keyboard shortcuts and slash commands). forge-agent is the Rust agent binary; outside headless mode it exits with a usage message and expects to be driven by a client — either forge-tui-rs or forge-ide, both of which drive the exact same binary independently.
If --cwd is not specified, Forge uses the current directory as the project root.
By default, Forge asks before writing files or running commands.
Approval behavior currently comes from several places:
- the TUI permission mode selector (
normal,auto_accept,plan) - per-session “approve always” memory for a tool after you choose that option
- the startup-wide bypass flag
forge-agent --dangerously-allow-all(typically used via theforgewrapper)
Set auto_approve_reads = true in config to silently allow all file reads.
Approval is not sandboxing. It is the only built-in safety barrier. If you approve a shell command or enable auto-approval, that command runs as your user on the host machine.
Forge supports two context management modes:
compaction— summarize older history with the model and keep a structured summaryrolling_window— drop the oldest messages directly without an extra LLM call
/revert is Git-backed. For local worktrees, Forge snapshots Git state at turn boundaries and can restore files plus conversation state to a selected user turn.
For remote work over SSH, use non-interactive commands such as ssh host 'cd /path/to/repo && command'. Before modifying files in a remote directory, Forge instructs the agent to verify that Git is installed and that the directory is inside a Git worktree. If Git is missing, the agent must ask before installing it unless the session was started with --dangerously-allow-all.
Forge loads built-in agent definitions (explore, bash, plan, general), then overrides them with any markdown files found in ~/.config/forge/agents/ and .agent/agents/ inside the project.
Forge loads custom shell-backed tools from ~/.config/forge/tools/ and .agent/tools/. Project tools override global tools with the same name.
Each tool needs a JSON definition plus an executable script (chmod +x run_linter.sh):
~/.config/forge/tools/
├── run_linter.json
└── run_linter.sh
{
"name": "run_linter",
"description": "Run the project linter and return concise output.",
"kind": "execute",
"script": "run_linter.sh",
"timeout_secs": 300,
"parameters": {
"type": "object",
"properties": {
"path": {
"type": "string",
"description": "Optional path to lint. Defaults to the project root."
}
}
}
}Forge runs the script from the project root. Tool arguments are passed as JSON on stdin and are also available in FORGE_TOOL_ARGS. Forge also sets FORGE_PROJECT_ROOT, FORGE_WORKING_DIR, and FORGE_TOOL_NAME.
kind controls approval behavior: read, write, or execute. Omit it and Forge treats the tool as execute.
"No endpoint 'X' found in config" — models.default in your config doesn't match any endpoint name. Open ~/.config/forge/config.toml and make sure models.default matches the name field of one of your [[models.endpoints]] entries.
Forge hangs on startup — your LLM server isn't running or the endpoint URL is wrong. Check that your server is up at the URL in your config, or re-run ./install.sh to reconfigure.
Config reset — delete ~/.config/forge/config.toml and re-run ./install.sh to go through the setup wizard again.
Occasional streamed-message truncation or duplication. Under some streaming conditions the assistant's reply can appear cut off or partially duplicated in the UI. This has been practically mitigated through streaming-parser fixes but still surfaces rarely. The full, authoritative version of every turn is preserved in .forge/sessions/{session_id}/conversation.jsonl regardless of how it rendered in the UI — so the session log is the source of truth if you suspect a display issue. Work in progress; please file an issue if you reproduce a case that lets us nail the remaining edge.
This is one project inside a larger monorepo — see the top-level README for how it relates to forge-tui and forge-ide, its two independent clients.
forge-agent/
├── src/
│ ├── main.rs Entry point, model/auth/bootstrap logic
│ ├── agent/
│ │ ├── core.rs Main agent loop, tool dispatch
│ │ ├── subagent.rs Parallel subagent runner
│ │ ├── compaction.rs Context compaction and rolling window helpers
│ ├── tools/
│ │ ├── executor.rs Tool execution + classification
│ │ ├── definitions.rs Tool JSON schemas
│ │ ├── web.rs Web tools
│ │ └── patch.rs Unified diff application
│ ├── api/
│ │ ├── client.rs OpenAI/Anthropic/ChatGPT client
│ │ └── types.rs Request/response types
│ ├── config.rs Config loading
│ └── headless.rs JSON protocol types
├── ARCHITECTURE.md Detailed architecture reference
├── ADDING_TOOLS.md Guide for adding new tools
└── install.sh Build + install script
See ADDING_TOOLS.md for the complete checklist. Every tool requires changes in definitions.rs, executor.rs, and core.rs at minimum.
forge-agent accepts --headless for programmatic use. It speaks a JSON newline protocol on stdin/stdout — see src/headless.rs for message types, and either ../forge-tui-rs/src/bridge.rs or ../forge-ide/src/agent_panel.rs for a reference client implementation. ChatGPT Codex OAuth login is also available through forge-agent --login-chatgpt.
Forge does not currently accept pull requests. The project is maintained by Vulkgryph LLC and contributions are closed to keep maintenance scope constrained.
Issues are welcome. If you have a fix or suggestion, include it in the issue itself — code snippet, patch, or written approach. If the suggested solution is used, you'll be credited in the commit and release notes.
For security issues, see SECURITY.md — please do not file public issues for vulnerabilities.
Forge is licensed under the Apache License, Version 2.0. See the NOTICE file for attribution.
Copyright © 2026 Vulkgryph LLC.
Forge is provided "AS IS", without warranty of any kind, express or implied, including but not limited to the warranties of merchantability, fitness for a particular purpose, and non-infringement.
Forge is a tool that reads, writes, and executes code on the user's machine. It can modify or delete files, run arbitrary shell commands, and call out to external LLM providers and other network services. In no event shall Vulkgryph LLC or any contributor be liable for any claim, damages, or other liability — whether in contract, tort, or otherwise — arising from the use of Forge, including but not limited to:
- Lost, corrupted, or overwritten files
- System damage or unintended state changes
- Commands executed by the agent that the user did not anticipate
- Leaked credentials, secrets, or API keys via model output, tool output, or session logs
- Financial costs incurred through LLM API or subscription usage
- Indirect, incidental, special, consequential, or punitive damages of any kind
Use of Forge implies acceptance of these terms. The full legal language is in LICENSE, which is the binding document; the plain-English summary above is provided for clarity, not as a replacement.