Autonomous AI agent orchestrator — Claude, Codex, Cursor-family CLIs, and the Responses API. Part of the Enact OS product line; replaced OMX-era surfaces with
enact-factorynaming so the pipeline is a Executor/Reviewer/Tester/Documenter assembly line, not a factory.
Enact Factory orchestrates multiple AI agents as autonomous code executors. It picks up workItems (from Azdo, GitHub, or a local workItem directory), runs Executor/Reviewer pair pipelines, reports to Discord, and retains long-term memory via LanceDB. Today the HTTP provider seam is the Responses API; CLI-backed agent surfaces remain the reference for full agent behavior until the Responses loop contract in docs/a_proposed/RESPONSES_AGENT_LOOP_SEMANTICS.md is implemented end to end.
Three nouns keep the system's concepts distinct. New readers should learn these before anything else:
| Noun | Meaning | Cardinality | Persistence |
|---|---|---|---|
| Operator | The lane driving a WorkItem's lifecycle | One per WorkItem | Durable on WorkItem (operatorLane field) |
| Stage | What the LLM is currently doing inside the operator | One per active turn | Transient (per-iteration) |
| Project | A sibling repo being orchestrated | N per Factory deployment | Config-defined |
Operator lanes (allowlisted values for operatorLane):
-
manual— operator explicitly opted out of automation -
none— no operator assigned -
autopilot— operator lane with durable state, phases, transitions, resume, and stop-policy parity -
ralph— generic loop operator (durable state, stop policy) -
ultrawork— WorkItem-aware loop operator (durable state, stop policy) -
team— collective operator (durable state, started viafactory_team_init)
Pipeline stages (values in autonomous.defaultStages):
-
coder— LLM generates code (wasexecutorin config; the packaged skill namedexecutorstays unchanged) -
critic— LLM reviews code (wasreviewerin config; the packaged skill namedreviewerstays unchanged) -
tester,documenter,auditor,stage-documenter— remaining pipeline stages (wasskill-documenter)
Important:
pipeline,swarm,ultrapilot,executor, andreviewerare NOT operator lane values.executorandreviewerare pipeline stages (and packaged skill names), not lanes.
This repo is internal-only (no npm publish). Build from source:
git clone <azure-devops-url>/enact-factory
cd enact-factory
npm install
npm run build
node dist/cli.jsThat's it. enact-factory with no arguments launches the TUI chat interface immediately.
| Key | Action |
|---|---|
Tab |
Switch tabs (Chat / Projects / Tasks / Stuck / Logs) |
Enter |
Send message |
Shift+Enter |
Newline |
i |
Focus input |
Esc |
Exit input focus |
Ctrl+C |
Quit |
Status bar shows: provider · model · message count · cumulative cost
enact-factory # TUI chat (default)
enact-factory chat [session] # Simple readline chat
enact-factory dash # Open dashboard only (UI + AzDO sync, no autonomous runner)
enact-factory start # Start full daemon (reads the root config.toml)
enact-factory run "Fix the bug" -p ~/my-project # Run a single task
enact-factory exec "Run tests" --local --pipeline # Execute via daemon
enact-factory init # Generate config.toml scaffold
enact-factory validate # Validate the active config.toml
# Code Registry & BS Detector
enact-factory check --scan # Scan repo → register all entities
enact-factory check src/foo.ts # File brief (entities, tests, risk)
enact-factory check --bs # BS pattern scan (bad code smells)
enact-factory check --stats # Registry statistics
enact-factory check --high-risk # High-risk entities
enact-factory check --search "name" # Full-text search
enact-factory annotate "funcName" --deprecate "reason"
enact-factory annotate "funcName" --tag "needs-refactor"
enact-factory annotate "funcName" --warn "error/security: SQL injection"enact-factory setup # Prompts project vs ~/.enact, then installs layout + Factory docs only
enact-factory setup --scope project # Skip prompt; install to <repo>/.enact/
enact-factory setup --no-ask # Skip prompt; use saved delivery scope
enact-factory doctor # Read readiness + ownership checks
enact-factory hud # Render text HUD from .enact/factory state
enact-factory task list # List mirrored Factory tasks
enact-factory session status # Show current Factory session
enact-factory team init # Initialize tmux/mock team state
enact-factory team status # Inspect team + tmux readiness
enact-factory plugins status # Inspect plugin marketplace/install state
enact-factory plugins list # List repo-local plugin scaffolds under <root>/extensions
enact-factory agents install # Install Factory AGENTS.md template into a target repo
enact-factory audit provider-boundary # Check memory/knowledge/provider narrowing
enact-factory uninstall # Remove Factory-owned Codex-facing setupThe Factory runtime assets ship from this repo, while host plugin delivery is owned by enact-extensions:
- Install host surfaces with
enact-extensions install enact-factory --platform <surface>or--platform all. - The canonical host plugin bundle lives in
/Users/tarunrana/Documents/Repos/enact-extensions/extensions/enact-factory. -
.agents/plugins/marketplace.jsonprovides the local marketplace surface. - Provider-boundary and replacement-readiness are enforced by the in-repo audit and doctor surfaces.
| Option | Description |
|---|---|
--path <path> |
Project path (default: cwd) |
--timeout <seconds> |
Timeout in seconds (default: 600) |
--local |
Execute locally without daemon |
--pipeline |
Full pipeline: executor + reviewer + tester + documenter |
--executor-only |
Executor only, no review |
-m, --model <model> |
Model override for executor |
Exit codes: 0 success · 1 failure · 2 timeout
For autonomous operation (Azdo workItem processing, Discord control, PR auto-improvement), you need a full config:
- Node.js >= 22
-
Claude Code CLI authenticated (
claude -p) — default provider -
OpenAI Codex CLI (
codex exec) — optional alternative provider - Discord Bot token with message content intent
- Azdo API key and team ID
-
GitHub CLI (
gh) for CI monitoring (optional)
git clone https://github.com/unohee/Enact-Factory.git
cd Enact-Factory
npm install
edit ../config.tomlCreate a .env file:
DISCORD_TOKEN=your-discord-bot-token
DISCORD_CHANNEL_ID=your-channel-id
# AzDo — all four required for live WorkItem round-tripping
AZDO_ORG=your-azdo-org
AZDO_PROJECT=your-azdo-project
AZDO_PAT=your-azdo-personal-access-token
AZDO_TEAM_ID=your-azdo-team-id
# AZDO_API_KEY is a legacy alias for AZDO_PAT (some surfaces still read it)
AZDO_API_KEY=${AZDO_PAT}The root config.toml supports ${VAR} / ${VAR:-default} substitution and is validated with Zod schemas.
Run these in order. Each step has a clear failure mode if skipped.
-
Build the dist tree. Factory runtime and MCP surfaces read compiled JS from
dist/. On a fresh clone before build, governance behavior is incomplete.pnpm build
-
Postgres reachable. WorkItem store backend is postgres per the root
config.toml(defaultlocalhost:45432, dbenact_factory_dev, user/pwenact:enact). The daemon won't start without it.pg_isready -h localhost -p 45432
-
AzDo env vars present. All four are required for the sync service and the manual drain MCP tool. Missing vars throw a clear error.
grep -E '^AZDO_(ORG|PROJECT|PAT|TEAM_ID)=' .env # expect 4 lines
-
Tests green. Sanity check the bridge before pointing it at production AzDo.
pnpm test # expect: Tests <N> passed | 6 skipped, 0 failed
-
Operator installed. Enact Operator owns hooks, operator skills, and Codex-facing lifecycle behavior.
enact-operator doctor
| Action | Expected flow |
|---|---|
| Create WorkItem in AzDo | Next syncOnce tick → local store gets it → visible via factory_workItem_get
|
Set operatorLane=ralph in AzDo |
Sync detects → observe queue entry → factory_workitem_observe proposes factory_skill_activate skill=ralph workItemId=...
|
| Start Ralph linked to the WorkItem |
factory_ralph_start workItemId=... stamps the link (rejects second link to different ID — call factory_ralph_unlink_workitem first) |
Advance Ralph running → verifying
|
Push queue gets { implementationComplete: true } entry → drainer pushes to AzDo on next sync tick → AzDo workItem shows the checkbox |
| Reviewer approves (lane-local WorkItem) |
recordTeamReview flips to completed + push reviewPassed: true → drainer pushes to AzDo |
| Reviewer approves (cross-repo Epic) |
canAutoClose guard fires → deferred ledger entry → status stays review → operator must call factory_workitem_acknowledge_close { workItemId, operatorOverrideReason } to record manual close |
| Try to stop with pending gates | Operator stop policy denies, writes a verdict, and the next session-start surfaces the warning |
| Manually drain pending lifecycle pushes |
factory_workitem_drain_push_queue MCP tool — returns { drained, errors[] }. Requires AZDO_ORG/AZDO_PROJECT/AZDO_PAT/AZDO_TEAM_ID. |
| Symptom | Likely cause | Fix |
|---|---|---|
| Sessions exit without the expected operator guardrails | Operator hooks are not installed or the runtime is stale | Reinstall/refresh Enact Operator and rebuild the runtime |
| AzDo workItem checkboxes never flip | Drainer can't reach AzDo | Check env vars + AzDo connectivity; factory_workitem_drain_push_queue for diagnostics |
Ultrawork already linked to "X" error |
Trying to retarget a primary parent | Call factory_ultrawork_unlink_workitem first (intentional invariant) |
Cross-repo Epic stuck at status: review after reviewer approval |
canAutoClose guard fired (correct) |
Call factory_workitem_acknowledge_close with a reason |
| §I4 closure-evidence-missing blocker fires repeatedly | Cross-repo Epic closed without acknowledgment | Either call factory_workitem_acknowledge_close, or use factory_stop_acknowledge for the session |
| Section | Description |
|---|---|
discord |
Bot token, channel ID, webhook URL |
azdo |
API key, team ID |
github |
Repos list for CI monitoring |
projects |
Project definitions (name, projectPath, heartbeat interval) |
autonomous |
Schedule, pair mode, stage models, decomposition settings |
adapter: claude # "claude" | "codex" | "responses" | "cursor" | "hermes" | "opencode"Switch at runtime via Discord: !provider codex / !provider claude
| Adapter | Backend | Models | Auth |
|---|---|---|---|
claude |
Claude Code CLI | sonnet-4, haiku-4.5, opus-4 | CLI auth |
codex |
OpenAI Codex CLI | o3, o4-mini | CLI auth |
responses |
/v1/responses server |
auto, gpt-4.1, gpt-4o, gpt-5, o3, o4-mini | Bearer env |
The Responses adapter can be configured with ENACT_GATEWAY_BASE_URL / ENACT_GATEWAY_API_KEY, or provider-specific ENACT_RESPONSES_* overrides. |
Per-stage adapter overrides:
autonomous:
defaultStages:
coder:
adapter: codex
model: o4-mini
critic:
adapter: claude
model: claude-sonnet-4-20250514autonomous:
defaultStages:
coder:
model: claude-haiku-4-5-20251001
escalateModel: claude-sonnet-4-20250514
escalateAfterIteration: 3
timeoutMs: 1800000
critic:
model: claude-haiku-4-5-20251001
timeoutMs: 600000
tester:
enabled: false
documenter:
enabled: false
auditor:
enabled: falsenpm run service:install # Build and install as system service
npm run service:start # Start
npm run service:stop # Stop
npm run service:restart # Restart
npm run service:status # Status and recent logs
npm run service:logs # stdout (follow mode)
npm run service:errors # stderr (follow mode)
npm run service:uninstall # Uninstallnpm run build && npm start # Production
npm run dev # Development (tsx watch)
docker compose up -d # Docker ┌──────────────────────────┐
│ Azdo API │
│ (workItems, state, memory) │
└─────────────┬────────────┘
│
┌─────────────────────┼─────────────────────┐
│ │ │
v v v
┌──────────────────┐ ┌──────────────────┐ ┌──────────────────┐
│ AutonomousRunner │ │ DecisionEngine │ │ TaskScheduler │
│ (heartbeat loop) │─>│ (scope guard) │─>│ (queue + slots) │
└────────┬─────────┘ └──────────────────┘ └────────┬─────────┘
│ │
v v
┌──────────────────────────────────────────────────────────────┐
│ PairPipeline │
│ ┌────────┐ ┌──────────┐ ┌────────┐ ┌─────────────┐ │
│ │ Executor │──>│ Reviewer │──>│ Tester │──>│ Documenter │ │
│ │(Adapter│<──│(Adapter) │ │(Adapter│ │ (Adapter) │ │
│ └───┬────┘ └──────────┘ └────────┘ └─────────────┘ │
│ │ ↕ StuckDetector │
│ ┌───┴────────────────────────────────────────────────────┐ │
│ │ Adapters: Claude | Codex | Responses | Cursor | Hermes | Opencode │ │
│ └────────────────────────────────────────────────────────┘ │
└──────────────────────────────────────────────────────────────┘
│ │ │
v v v
┌──────────────┐ ┌──────────────────┐ ┌──────────────────┐
│ Discord Bot │ │ Memory (LanceDB │ │ Knowledge Graph │
│ (commands) │ │ + Xenova E5) │ │ (code analysis) │
└──────────────┘ └──────────────────┘ └────────┬─────────┘
│
┌────────┴─────────┐
│ Code Registry │
│ (SQLite + FTS5) │
│ + BS Detector │
└──────────────────┘
- Multi-Provider Adapters — Pluggable adapter system: Claude Code, Codex, Responses API, Cursor, Hermes, and Opencode
- Code Registry — SQLite-backed entity registry tracking every function/class/type across 8 languages, with complexity scoring, test mapping, and risk assessment
- WorkItem Store — PostgreSQL-backed work-item persistence and Kanban UI, with SQLite kept only as a legacy fallback path
-
BS Detector — Built-in static analysis engine that detects bad code patterns (empty catch, hardcoded secrets,
as any, etc.) with pipeline guard integration - Autonomous Pipeline — Cron-driven heartbeat fetches Azdo workItems, runs Executor/Reviewer pair loops, and updates workItem state automatically
- Executor/Reviewer Pairs — Multi-iteration code generation with automated review, testing, and documentation stages
- Decision Engine — Scope validation, rate limiting, priority-based task selection, and workflow mapping
- Cognitive Memory — LanceDB vector store with Xenova/multilingual-e5-base embeddings for long-term recall across sessions
- Knowledge Graph — Static code analysis, dependency mapping, impact analysis, and file-level conflict detection across concurrent tasks
- Discord Control — Full command interface for monitoring, task dispatch, scheduling, provider switching, and pair session management
- Rich TUI Chat — Claude Code inspired terminal interface with tabs, streaming responses, and geek-themed loading messages
- Dynamic Scheduling — Cron-based job scheduler with Discord management commands
- PR Auto-Improvement — Monitors open PRs, auto-fixes CI failures, auto-resolves merge conflicts, and retries until all checks pass
- Long-Running Monitors — Track external processes (training jobs, batch tasks) and report completion
- Web Dashboard — Real-time pipeline stages, cost tracking, worktree status, and live logs on port 3847
- Pace Control — 5-hour rolling window task caps, per-project limits, turbo mode, exponential backoff on failures
- i18n — English and Korean locale support
Azdo (Todo/In Progress)
→ Fetch assigned workItems
→ DecisionEngine filters & prioritizes
→ Resolve project path via projectMapper
→ PairPipeline.run()
→ Executor generates code (Claude CLI)
→ Reviewer evaluates (APPROVE/REVISE/REJECT)
→ Loop up to N iterations
→ Optional: Tester → Documenter stages
→ Update Azdo workItem state (Done/Blocked)
→ Report to Discord
→ Save to cognitive memory
Hybrid retrieval: 0.55 × similarity + 0.20 × importance + 0.15 × recency + 0.10 × frequency
Memory types: belief · strategy · user_model · system_pattern · constraint
Background: decay, consolidation, contradiction detection, distillation.
| Command | Description |
|---|---|
!dev <repo> "<task>" |
Run a dev task on a repository |
!dev list |
List known repositories |
!tasks |
List running tasks |
!cancel <taskId> |
Cancel a running task |
| Command | Description |
|---|---|
!status |
Agent and system status |
!pause <session> |
Pause autonomous work |
!resume <session> |
Resume autonomous work |
!log <session> [lines] |
View recent output |
| Command | Description |
|---|---|
!workItems |
List Azdo workItems |
!workItem <id> |
View workItem details |
!limits |
Agent daily execution limits |
| Command | Description |
|---|---|
!auto |
Execution status |
!auto start [cron] [--pair] |
Start autonomous mode |
!auto stop |
Stop autonomous mode |
!auto run |
Trigger immediate heartbeat |
!approve / !reject
|
Approve or reject pending task |
| Command | Description |
|---|---|
!pair |
Pair session status |
!pair start [taskId] |
Start a pair session |
!pair run <taskId> [project] |
Direct pair run |
!pair stop [sessionId] |
Stop a pair session |
!pair history [n] |
View session history |
!pair stats |
View pair statistics |
| Command | Description |
|---|---|
!schedule |
List all schedules |
!schedule run <name> |
Run a schedule immediately |
!schedule toggle <name> |
Enable/disable a schedule |
!schedule add <name> <path> <interval> "<prompt>" |
Add a schedule |
!schedule remove <name> |
Remove a schedule |
| Command | Description |
|---|---|
!ci |
GitHub CI failure status |
!provider <claude|codex> |
Switch CLI provider at runtime |
!codex |
Recent session records |
!memory search "<query>" |
Search cognitive memory |
!help |
Full command reference |
src/
├── index.ts # Entry point
├── cli.ts # CLI entry point (run, exec, chat, init, validate, start)
├── cli/ # CLI subcommand handlers
│ └── promptHandler.ts # exec command: daemon submit, auto-start, polling
├── core/ # Config, service lifecycle, types, event hub
├── adapters/ # CLI/provider adapters (claude, codex, responses), process registry
├── agents/ # Executor, reviewer, tester, documenter, auditor
│ ├── pairPipeline.ts # Executor → Reviewer → Tester → Documenter pipeline
│ ├── agentBus.ts # Inter-agent message bus
│ └── cliStreamParser.ts # Claude CLI output parser
├── orchestration/ # Decision engine, task parser, scheduler, workflow
├── automation/ # Autonomous runner, cron scheduler, PR processor
├── memory/ # LanceDB + Xenova embeddings cognitive memory
├── knowledge/ # Code knowledge graph (scanner, analyzer, graph)
├── registry/ # Code entity registry, BS detector, entity scanner
├── workItems/ # Postgres-first workItem tracker (GraphQL + Kanban UI)
├── discord/ # Bot core, command handlers, pair session UI
├── azdo/ # Azdo SDK wrapper, project updater
├── github/ # GitHub CLI wrapper for CI monitoring
├── support/ # Web dashboard, planner, rollback, git tools
├── locale/ # i18n (en/ko) with prompt templates
└── __tests__/ # Vitest test suite
| Path | Description |
|---|---|
.enact/factory/ |
Repo-local Factory state directory (cache, logs, memory, plans, reports, research, sessions, state, team, ultragoal) |
.enact/factory/state/registry.db |
Code entity registry (SQLite) |
.enact/factory/state/workItems.db |
PostgreSQL workItem store (root config.toml; legacy SQLite fallback only if explicitly configured) |
~/.claude/enact-factory-*.json |
Pipeline history and task state |
../config.toml |
Canonical workspace configuration |
dist/ |
Compiled output |
| Category | Technology |
|---|---|
| Runtime | Node.js 22+ (ESM) |
| Language | TypeScript (strict mode) |
| Build | tsc |
| Agent Execution | Claude Code, Codex, Responses API, Cursor, Hermes, Opencode |
| WorkItem Store | PostgreSQL (default) |
| Code Registry DB | better-sqlite3 (WAL mode, FTS5) |
| Task Management | Azdo SDK (@azdo/sdk) |
| Communication | Discord.js 14 |
| Vector DB | LanceDB + Apache Arrow |
| Embeddings | Xenova/transformers (multilingual-e5-base, 768D) |
| Scheduling | Croner |
| Config | YAML + Zod validation |
| Linting | oxlint |
| Testing | Vitest |
-
Code Registry:
enact-factory check --scanscans repo, registers 1000+ entities across 8 languages (TS, Python, Go, Rust, Java, C, C++, C#) with test mapping, complexity scoring, and risk assessment -
BS Detector:
enact-factory check --bs— built-in static analysis for bad code patterns, pipeline guard integration -
Responses Adapter: Gateway-backed
/v1/responsesexecution with env-based bearer auth -
Responses Status: Transport works today, but full agent parity is deferred until the loop semantics in
docs/a_proposed/RESPONSES_AGENT_LOOP_SEMANTICS.mdland -
WorkItem Tracker: PostgreSQL + GraphQL + Kanban web UI at
:3847/workItems -
CLI:
enact-factory check,enact-factory annotatecommands
-
enact-factorywithout arguments now launches TUI chat directly
- Security: patched lodash, picomatch, rollup, undici, yaml vulnerabilities
- Multi-project orchestration via Azdo ticket routing
- Standalone driver module extracted for reuse
- Autonomous runner hardening and multi-project orchestration
- Task-state rehydration from Azdo comments
-
--verboseflag for detailed execution logging - Codex adapter: dropped o-series model override
- Initial release
- Executor/Reviewer pair pipeline
- Claude Code CLI, Codex, Cursor-family adapters, and a Responses API seam
- Discord bot control
- Azdo integration
- LanceDB cognitive memory
- Web dashboard (port 3847)
- Rich TUI chat interface
This project is licensed under the proprietary Agent Development License (ADL).
See LICENSE for full terms.
© Enact Factory. All rights reserved.
