@amsterdamdatalabs/enact-factory
TypeScript icon, indicating that this package has built-in type declarations

0.1.1 • Public • Published

Enact Factory

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-factory naming 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.

Vocabulary

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 via factory_team_init)

Pipeline stages (values in autonomous.defaultStages):

  • coder — LLM generates code (was executor in config; the packaged skill named executor stays unchanged)
  • critic — LLM reviews code (was reviewer in config; the packaged skill named reviewer stays unchanged)
  • tester, documenter, auditor, stage-documenter — remaining pipeline stages (was skill-documenter)

Important: pipeline, swarm, ultrapilot, executor, and reviewer are NOT operator lane values. executor and reviewer are pipeline stages (and packaged skill names), not lanes.

Quick Start

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.js

That's it. enact-factory with no arguments launches the TUI chat interface immediately.

TUI Chat Interface

TUI keyboard shortcuts

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


CLI Commands

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 surface

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 setup

The 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.json provides the local marketplace surface.
  • Provider-boundary and replacement-readiness are enforced by the in-repo audit and doctor surfaces.

enact-factory exec options

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


Full Daemon Setup

For autonomous operation (Azdo workItem processing, Discord control, PR auto-improvement), you need a full config:

Prerequisites

  • 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)

Configuration

git clone https://github.com/unohee/Enact-Factory.git
cd Enact-Factory
npm install
edit ../config.toml

Create 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.

Pre-flight checklist (before first live run)

Run these in order. Each step has a clear failure mode if skipped.

  1. 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
  2. Postgres reachable. WorkItem store backend is postgres per the root config.toml (default localhost:45432, db enact_factory_dev, user/pw enact:enact). The daemon won't start without it.

    pg_isready -h localhost -p 45432
  3. 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
  4. Tests green. Sanity check the bridge before pointing it at production AzDo.

    pnpm test
    # expect: Tests <N> passed | 6 skipped, 0 failed
  5. Operator installed. Enact Operator owns hooks, operator skills, and Codex-facing lifecycle behavior.

    enact-operator doctor

What you should see end-to-end

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.

Common failure modes

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

Key configuration sections

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

CLI Adapter (Provider)

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-20250514

Pipeline Stages

autonomous:
  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: false

Running the daemon

macOS launchd service (recommended)

npm 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  # Uninstall

Manual

npm run build && npm start   # Production
npm run dev                  # Development (tsx watch)
docker compose up -d         # Docker

Architecture

                         ┌──────────────────────────┐
                         │       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   │
                                           └──────────────────┘

Features

  • 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

How It Works

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

Memory System

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.


Discord Commands

Task Dispatch

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

Agent Management

Command Description
!status Agent and system status
!pause <session> Pause autonomous work
!resume <session> Resume autonomous work
!log <session> [lines] View recent output

Azdo Integration

Command Description
!workItems List Azdo workItems
!workItem <id> View workItem details
!limits Agent daily execution limits

Autonomous Execution

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

Executor/Reviewer Pair

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

Scheduling

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

Other

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

Project Structure

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

State & Data

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

Tech Stack

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

Changelog

v0.3.0

  • Code Registry: enact-factory check --scan scans 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/responses execution 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.md land
  • WorkItem Tracker: PostgreSQL + GraphQL + Kanban web UI at :3847/workItems
  • CLI: enact-factory check, enact-factory annotate commands

v0.2.2

  • enact-factory without arguments now launches TUI chat directly

v0.2.1

  • Security: patched lodash, picomatch, rollup, undici, yaml vulnerabilities

v0.2.0

  • 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
  • --verbose flag for detailed execution logging
  • Codex adapter: dropped o-series model override

v0.1.0

  • 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

License

This project is licensed under the proprietary Agent Development License (ADL).
See LICENSE for full terms.

© Enact Factory. All rights reserved.

Readme

Keywords

none