Factory¶
The Rose Factory runs assigned Linear tickets through coding agents (Claude
Code, Codex) in isolated git worktrees. It is a standalone, pipx-installable
tool (rose-factory) with no dependency on the rest of the monorepo — see
factory/README.md
for the full command reference and Factory: local setup to run it.
It has two planes:
- Orchestrator (
factory/orchestrator/) — declares agents, owns Linear routing, scheduling, and the retry/reconciliation/status lifecycle. Runs as a local polling loop; engine runs execute locally per machine. - Relay (
factory/relay/) — a small HTTP service (Cloud Run, or local) for the Linear-Agents (agent_session) OAuth + webhook path. The only hosted component.
The runner (factory/runner/) is the engine-neutral per-issue interface; engine
adapters live under factory/engines/ (Claude, Codex, and a console smoke-test runner).
Architecture¶
Two tracker modes per agent:
api_key— the orchestrator polls the Linear API directly with the agent's token.agent_session— Linear delivers webhooks to the relay; the worker long-polls the relay's/eventsinstead of polling Linear. See the relay section offactory/README.mdfor local webhook setup (cloudflared tunnel).
Workspaces¶
Each issue runs in its own git worktree. A standalone install has no local
checkout, so the factory keeps one base clone per repo per machine
(~/rose-factory/repos/<slug>), fetches it each tick, and adds per-issue
worktrees from it. The target repo + base ref + bootstrap command come from the
agent's repo config in ~/rose-factory/agents.yaml. Passing --repo-root <path>
uses an existing local checkout instead (in-monorepo dev).
Continuous orchestrator¶
The orchestrator polls Linear (or long-polls the relay) with the declared agent
token, dispatches changed assigned issues to the configured runner, and records
the last processed Linear updatedAt in ~/rose-factory/state.json.
rose-factory start --agent benoit-codex # one agent
rose-factory start # all declared agents
rose-factory start --once --dry-run --agent X # validate routing, no engine
When a reviewer comments on the ticket, Linear updates the issue; the next poll
rebuilds the prompt with recent comments and reruns the runner in the same issue
workspace. On start the orchestrator transitions the issue to In Progress; on
finish it transitions to In Review (on success) and posts one human-facing
summary comment. Factory-authored comments carry a hidden marker and are excluded
from future prompts. A ticket left In Progress with no live owner is
auto-recovered on a later tick (resume once, then escalate).
Claude and Codex runners use logged-in CLI/subscription auth, not provider API
keys. Engine subprocess environments strip common LLM API-key variables
(OPENAI_API_KEY, ANTHROPIC_API_KEY, …); Linear tokens are used only by the
orchestrator/tracker layer.
Runtime environments¶
Runtime environments are separate from engines and transports. The first provider
is none, which provisions no preview and runs the engine in a worktree. Later
providers such as google_preview can add Supabase preview branches, Cloud Run
tagged revisions, frontend bundles, and Cloudflare preview routes without changing
orchestrator routing semantics.
Run as a service¶
rose-factory install-daemon wraps any command in the OS service manager
(launchd on macOS, systemd --user on Linux) so it auto-starts and restarts on
crash:
rose-factory install-daemon --env-file ~/rose-factory/daemon.env -- start
rose-factory install-daemon --name rose-relay --env-file ~/rose-factory/daemon.env -- relay --local-queue
Secrets¶
Resolved env-first, then GCP Secret Manager (relay only). Set the value as an env var named by the config key for a no-GCP run.
| Secret | Purpose |
|---|---|
CLAUDE_AUTH_TOKEN |
Claude Code Max subscription auth |
FACTORY_GITHUB_TOKEN |
GitHub clone/push/PR (private repos) |
LINEAR_API_KEY |
Linear API for api_key agents |
FACTORY_RELAY_WORKER_TOKEN |
Worker bearer token for agent_session agents |
LANGFUSE_*, SENTRY_AUTH_TOKEN, SUPABASE_ACCESS_TOKEN |
Observability / MCP (optional) |