@ipul-labs/forge
v1.21.1
Published
AI-powered code change & deploy control panel — connects Claude, GitLab, and Kubernetes
Downloads
2,821
Maintainers
Readme
Forge by iPuL
AI-powered code change & deploy control panel. Connect an issue tracker, let Claude propose a fix, review the diff, approve — and Forge creates the branch, commits the changes, opens the MR/PR, and monitors the CI pipeline.
Built on: Claude Code CLI · GitLab / GitHub / Azure DevOps · Kubernetes
Why Forge
The CI refinement loop is the thing. Every other AI coding tool hands off after the PR is open. Forge keeps going: when your pipeline fails, it grabs the last 150 lines of the failed job log, feeds them back to Claude with the original fix context, generates a targeted patch, and commits it to the branch — automatically. No human has to read the stack trace, translate it into a prompt, and paste it somewhere. The loop closes itself.
Everything else fills in the gaps that matter for real teams:
- No per-token cost — Claude runs via the
claudeCLI using your existing Claude subscription, not API credits. Heavy use doesn't trigger a bill. - Multi-provider — GitLab, GitHub, and Azure DevOps are all first-class. Switch providers with a single env var; all normalized data shapes stay the same.
- Self-hosted — your code never leaves your infrastructure. The backend runs wherever you deploy it; AI calls go to Anthropic (or a local gateway via OpenClaw).
- Two-pass analysis keeps context focused — Claude first identifies the 6 most relevant files, then reads only those when proposing the fix. This produces sharper diffs than dumping the whole repo into one prompt.
How it works
- Connect — enter your Forge token to authenticate
- Pick an issue — Forge loads open issues from your project
- Analyze — Claude reads the repo file tree, identifies relevant files, and proposes a targeted fix
- Review — inspect the diff file-by-file; refine with natural-language feedback if needed
- Apply — Forge creates a branch, commits all changes, and opens a merge/pull request
- Monitor — watch the CI pipeline run; if it fails, click "Fix with AI" to iterate
Getting started
Prerequisites
- Node.js 20+
claudeCLI installed and authenticated (claude auth login)- Credentials for your SCM provider (see Configuration)
Install
git clone https://gitlab.com/ipul-labs/forge.git
cd forge
npm installConfigure
# Interactive setup — writes .env and ~/.forge/config.json
npx forge initOr copy the example env and fill in the values manually:
cp .env.example .env
# fill in FORGE_TOKEN plus your provider credentialsLaunch the UI
npm run dev
# opens http://localhost:5000 (frontend) with API on :5001For production:
npm run build:app # builds Vite SPA to dist/
npm start # NODE_ENV=production node server.jsCLI usage
The forge CLI drives the same orchestrator from the terminal. Install globally or use npx:
# Global install (adds `forge` to PATH)
npm install -g @ipul-labs/forge
# Or run via npx from the repo
npx forge <command>Interactive mode
Run forge with no arguments to enter an interactive terminal session:
forge forge v1.15.1
──────────────────────────────────────────────────
❯ issues --limit 5
──────────────────────────────────────────────────
group/repo | agent:claude | v1.15.1Tab-completes command names. Type use <repo> to switch repos. Commands that error stay in the session — only exit, quit, or Ctrl+D leave.
End-to-end: issue to production
forge ship 42Runs: analyze → review → validate → apply → watch CI → merge → watch deploy → close, with a y/N gate at every state-changing step.
Step-by-step commands
forge issues # List open issues (--label X, --mine, --limit N)
forge issue 42 # Show full description
forge create-issue --title "fix: broken widget" # Create a new issue
forge analyze 42 # Run two-pass analysis, cache result
forge show # Re-render cached analysis
forge refine --feedback "..." # Iterate with feedback
forge validate # Run lint/typecheck/test against proposed changes
forge apply # Push branch + open MR
forge watch # Poll the MR pipeline
forge ci-fix # Re-analyze with failed-pipeline logs
forge merge # Merge the MR
forge resolution-check # Verify merged MR closes the issue
forge close # Close the issue
forge use group/other-repo # Switch active repo
forge update # Pull latest + reinstall dependencies
forge stats # View telemetry — success rates, timing, failure patterns
forge improve # Evaluate patterns and suggest improvements
forge improve --create # Create improvement issues in the repoOptions
-p, --port <n> Port for start
--repo <group/repo> Primary repo
--secondary <repo> Additional repo (repeatable)
--all-repos Include every configured repo
--model <id> Claude model override
--agent <name> Agent backend: claude | openclaw
--prompt <text> Extra user prompt
--json JSON output
--quiet Suppress progress
--yes Skip confirmation gates
--validate Run validate before applyDiagnostics
forge doctor # Check prerequisites (node, claude CLI, env vars)
forge session list # List cached sessions
forge session clean # Remove stale session dataSee docs/cli.md for the full command reference and docs/cli-ship-workflow.md for the workflow design.
Configuration
Core
| Variable | Required | Description |
|---|---|---|
| FORGE_TOKEN | Yes | Dashboard password — also auto-fills the UI login form |
| FORGE_REPOS | Yes | Comma-separated repo list; first entry is the primary project |
| SCM_PROVIDER | — | gitlab (default) · github · azuredevops |
| ANTHROPIC_API_KEY | — | Enables live model list from Anthropic; falls back to hardcoded list |
| FORGE_MODEL | — | Override default model (default: claude-sonnet-4-6) |
| K8S_CLUSTER_TOKEN | — | K8s service account token for rollout monitoring |
| K8S_CLUSTER_SERVER | — | K8s API server URL |
| PORT | — | HTTP server port (default: 5001) |
| OPENCLAW_GATEWAY_URL | — | Enables OpenClaw agent backend; point at your local Gateway |
| OPENCLAW_TOKEN | — | Bearer token for OpenClaw Gateway auth |
Provider credentials
SCM tokens can be set here or in the Forge Settings UI (Settings → Connections). The UI value takes precedence over env vars.
GitLab (SCM_PROVIDER=gitlab, default)
| Variable | Required | Description |
|---|---|---|
| GITLAB_TOKEN | Yes | Personal access token with api + write_repository scopes |
GitHub (SCM_PROVIDER=github)
| Variable | Required | Description |
|---|---|---|
| GITHUB_TOKEN | Yes | Personal access token with repo + workflow scopes |
| GITHUB_OWNER | Yes | Organization or user, e.g. ipul-labs |
| GITHUB_REPO | Yes | Repository name, e.g. web-app |
| GITHUB_BASE_BRANCH | — | Default target branch (default: main) |
Azure DevOps (SCM_PROVIDER=azuredevops)
| Variable | Required | Description |
|---|---|---|
| AZURE_DEVOPS_TOKEN | Yes | Personal access token (Full access or Code + Work Items) |
| AZURE_DEVOPS_ORG | Yes | Organization name, e.g. ipul-labs |
| AZURE_DEVOPS_PROJECT | Yes | Team project name, e.g. web-app |
| AZURE_DEVOPS_REPO | — | Git repo name (defaults to project name) |
| AZURE_DEVOPS_BASE_BRANCH | — | Default target branch (default: main) |
Deprecated (still work as fallbacks)
| Variable | Replaced by |
|---|---|
| FORGE_GITLAB_PROJECT | First entry in FORGE_REPOS |
| VITE_FORGE_TOKEN | Auto-derived from FORGE_TOKEN |
| FORGE_REFINE_REPO_ACCESS | Settings UI toggle (Settings → Defaults) |
See .env.example for a full annotated list.
Multi-provider support
Forge's SCM layer is a clean provider abstraction — all three providers implement the same ScmProvider interface and return identical normalized shapes (NormalIssue, NormalMR, NormalPipeline, etc.). The rest of the codebase never knows which provider is active.
Switching providers
# .env
SCM_PROVIDER=github
GITHUB_TOKEN=ghp_...
GITHUB_OWNER=my-org
GITHUB_REPO=my-repoPer-repo prefix (multi-repo mixed-provider setups)
FORGE_REPOS=gitlab:ipul/web-app,github:my-org/mobileProvider capabilities
| Feature | GitLab | GitHub | Azure DevOps | |---|---|---|---| | Issues / Work Items | Yes | Yes | Yes (Work Items) | | Multi-file commits | Yes | Yes (Git Data API) | Yes (Pushes API) | | Merge / Pull Requests | Yes | Yes | Yes | | CI pipelines | Yes (GitLab CI) | Yes (GitHub Actions) | Yes (Azure Pipelines) | | Job log traces | Yes | Yes | Yes | | Server-side rebase | Yes | — | — |
Self-improvement
Forge monitors its own performance and proposes fixes autonomously. The loop:
- Telemetry — every operation records success/fail, duration, tokens, and cost to
~/.forge/telemetry/ - Pattern detection — recurring failures are grouped and classified (timeout-tuning, provider-bug, prompt-quality, validation-gap, error-handling, ux-improvement)
- Auto-evaluation — runs automatically after every 25 operations (4-hour cooldown). High-severity patterns trigger issue creation.
- Issue creation — files issues in the configured repo with diagnosis, evidence, and suggested fixes. Tagged
[self-improve]with category labels. - Human review — Forge never auto-merges its own changes. All improvements go through normal MR review.
- Resolution — when a self-improve issue is closed, matching telemetry failure patterns are marked as resolved. They stop appearing in
forge statsand won't trigger duplicate diagnoses. Resolution is tied to code state, not time — patterns only clear when the fix ships.
forge stats # View telemetry data
forge improve # Run evaluation manually
forge improve --create # Create issues for actionable patterns
forge improve --ship # Create issues + analyze + propose fix + open MR
forge improve --json # Pipe-friendly outputThe --ship flag runs the full loop: detect pattern → create issue → analyze → propose fix → open MR. All in one command. The MR goes through normal CI — you review and merge or reject.
UX insights are also derived from telemetry: slow operations (>2 min avg), high token usage (>50k avg), and frequent cancellations surface as improvement suggestions.
Security
Forge is designed for self-hosted deployment on trusted infrastructure. Security measures in place:
- Timing-safe auth — token comparison uses
crypto.timingSafeEqualto prevent timing attacks - Rate limiting — API endpoints are rate-limited (60 req/min per IP) to prevent brute-force
- Security headers — Helmet middleware sets X-Frame-Options, HSTS, X-Content-Type-Options, and CSP (production)
- Request size limits — JSON body capped at 1MB to prevent memory exhaustion
- Secret redaction — error logs and API responses scrub tokens (
glpat-*,ghp_*,oauth2:*@) before output - File permissions — config files (
~/.forge/config.json) written with0600, session directories with0700 - Git credential isolation — SCM tokens passed via
GIT_ASKPASShelper, never embedded in clone URLs - Path traversal protection — symlink-aware
realpathchecks prevent file writes outside clone directories - No shell injection — all subprocess calls use
spawn()with argument arrays, never shell strings - Atomic config writes — config updates use temp file + rename to prevent corruption
FORGE_TOKEN is a standalone dashboard password — never reuse an SCM token for this value.
Production deployment
npm run build:app # builds Vite SPA to dist/
NODE_ENV=production tsx server.tsOr with Docker:
docker build -t forge .
docker run -p 5001:5001 --env-file .env forgeArchitecture
Full-stack TypeScript. The backend runs via tsx (no build step); the frontend compiles through Vite.
bin/
forge-agent.ts # CLI entry point (forge command)
cli/
ship.ts # End-to-end orchestrator (Ink UI)
analyze.ts # Two-pass issue analysis
repl.ts # Interactive terminal (Ink-based)
serverClient.ts # CLI → Server API client (server/local mode)
sessionStore.ts # ~/.forge/sessions/ persistence
...
shared/
events.ts # FORGE_EVENTS constants (server + client)
server/
forge/
routes.ts # Express router — all /api/forge/* endpoints
core/
ForgeAgent.ts # Orchestrates the full pipeline (analyze -> apply -> refine)
claudeClient.ts # Shells out to the claude CLI for structured output
openclawClient.ts # OpenClaw Gateway HTTP client
agentClient.ts # Dispatcher: routes to claudeClient or openclawClient
k8s.ts # Kubernetes client for rollout monitoring
jobs.ts # Job store with SSE event buffering + replay
providers/
base.ts # Abstract ScmProvider — normalized shapes + interface
gitlab.ts # GitLab REST API v4
github.ts # GitHub REST API v3 + Git Data API
azuredevops.ts # Azure DevOps REST API
index.ts # createProvider() factory
src/
views/Forge/
ForgeDashboard.tsx # Root UI component with tabbed issue/MR views
api.ts # Token management + fetch helper
types.ts # Shared TypeScript types
utils.ts # SSE helper + state utilities
components/ # Analysis progress, pipeline status, diff viewer
hooks/
useForgeDashboard.ts # All state, phase transitions, and API calls
useForgeEvents.ts # SSE event bus subscriptionTwo-pass analysis
Pass 1 — identifyRelevantFiles: Claude reads the issue + file tree, returns the max-6 most relevant paths.
Pass 2 — proposeFix: Claude reads the actual file contents and proposes a targeted fix as a JSON diff.
Both passes use claude --print --output-format json so cost and service tier are tracked automatically.
CI refinement
When a pipeline fails, Forge fetches the last 150 lines of each failed job's trace log and feeds them to pass 2 with an explicit "pipeline failed" framing — not generic reviewer feedback. This improves fix quality for common failures like lint errors and type errors.
Provider abstraction
All three SCM providers implement ScmProvider from providers/base.ts. The contract is:
- Normalized return types — all methods return
NormalIssue,NormalMR,NormalPipeline, etc., regardless of provider - Instance-scoped — each provider is instantiated with a repo string; no global state
supportsRebase— providers that don't support server-side rebase returnfalse; the UI and API layer check this before showing the rebase button
Programmatic usage
The npm package ships compiled JavaScript with TypeScript declarations — no tsx or TypeScript runtime needed by consumers.
import forgeRouter from "@ipul-labs/forge"; // Express router
import { ForgeAgent } from "@ipul-labs/forge/agent"; // Core pipeline class
import { createProvider } from "@ipul-labs/forge/providers"; // SCM factoryconst agent = new ForgeAgent({ project: "group/repo" });
const result = await agent.analyzeIssue(42, (event) => console.log(event));
const { branchName, mr } = await agent.applyFix(result);Development
Source is TypeScript (.ts). The dev server runs via tsx (no build step). For the npm package, tsc compiles to lib/ with declarations during prepack.
npm run dev # tsx watch + vite (dev)
npm run build:server # compile server/bin/shared → lib/
npm run typecheck # check both frontend + server configsLicense
MIT
