@telora/daemon
v0.15.50
Published
Agent orchestration daemon for Telora - spawns and manages Claude Code instances
Maintainers
Readme
@telora/daemon
Agent orchestration daemon for Telora - spawns and manages Claude Code instances to work on deliveries autonomously.
Overview
The Telora daemon watches for active focuses in your Telora organization and spawns Claude Code Agent Teams to execute them. Each focus gets a single Agent Team that coordinates work across all deliveries and issues.
Key features:
- Focus-level Agent Teams: One team per focus manages all deliveries, building a task DAG and coordinating parallel execution
- Multi-repo support: Multiple daemons can run against the same Telora org, each handling focuses for different repos
- Integration branch workflow: Teams work on isolated branches, auto-merge to integration on success
- Worktree isolation: Each team gets its own git worktree
- Dynamic delivery pickup: Teams detect and incorporate new deliveries added mid-execution
Installation
For long-running daemon hosts, install globally so telora-daemon update and the in-process auto-updater can replace the binary in place:
npm install -g @telora/daemonnpx-based runs are supported for one-shot setup and short-lived experiments, but the npx cache makes the running binary effectively immutable: npm install -g writes to the global prefix while the process keeps loading the cached copy. In npx mode, auto-update is disabled, and telora-daemon update clears the cache and asks you to re-launch.
Note: The
.mcp.jsonfile for Claude Code integration is auto-generated bytelora-daemon init.
Quick Start
Option 1: Interactive Setup (Recommended)
npm install -g @telora/daemon
cd /path/to/your/repo
telora-daemon initThe setup wizard will guide you through:
- Telora URL configuration
- Organization ID
- Integration branch name
- Max concurrent agents
Then set your tracker ID and start the daemon:
export TELORA_TRACKER_ID=your-tracker-id-here
telora-daemon runOption 2: Manual Setup
Get your Tracker ID from Telora:
- Go to Settings → AI Work Trackers
- Click "Generate Tracker ID" on your profile
- Copy the tracker ID
Configure environment variables in your repo:
cd /path/to/your/repo
# Create .env file
cat > .env << EOF
TELORA_URL=https://your-telora-instance.supabase.co
TELORA_TRACKER_ID=your-tracker-id-here
TELORA_ORGANIZATION_ID=your-org-id-here
EOF- Start the daemon:
telora-daemon runOption 3: One-shot via npx
npx -p @telora/daemon telora-daemon init # interactive setup
npx -p @telora/daemon telora-daemon run # start the daemonThis is fine for trying things out, but use npm install -g @telora/daemon for any host you expect to leave running -- otherwise the daemon won't be able to update itself.
Updating
telora-daemon check-update # report whether a newer version exists
telora-daemon update # stop, install latest, apply migrations, restartWhen installed globally or from a git checkout, the daemon also self-updates on a periodic timer (configurable via autoUpdate.intervalMs in .telora/daemon.json, or disable with --no-auto-update).
In npx-cache mode, telora-daemon update clears the cache and prints the command to re-launch from a fresh fetch -- automatic restart isn't possible because the running process is loading from a directory that no longer exists.
Configuration
The daemon is configured via environment variables:
| Variable | Required | Default | Description |
|----------|----------|---------|-------------|
| TELORA_URL | Yes | - | Telora API URL |
| TELORA_TRACKER_ID | Yes | - | Your tracker ID for authentication |
| TELORA_ORGANIZATION_ID | Yes | - | Organization to watch for work |
| TELORA_REPO_PATH | No | cwd() | Path to git repository |
| TELORA_INTEGRATION_BRANCH | No | integration | Branch for agent merges |
| TELORA_WORKTREE_DIR | No | .telora/worktrees | Directory for git worktrees |
| TELORA_LOG_DIR | No | .telora/logs | Directory for agent logs |
| CLAUDE_CODE_PATH | No | claude | Path to Claude Code executable |
| MAX_TOTAL_SESSIONS | No | 5 | Max concurrent agents |
| SESSION_TIMEOUT_MS | No | 3600000 | Session timeout (1 hour) |
| TOKEN_LIMIT | No | 200000 | Max tokens per session |
| COST_LIMIT | No | 10.0 | Max cost per session ($) |
CLI Options
telora-daemon [options]
Options:
-V, --version Output version number
-v, --verbose Enable verbose logging
-c, --config <path> Path to config file (default: .telora/daemon.json)
--dry-run Print configuration and exit
-h, --help Display helpConfig File
Instead of environment variables, you can use a JSON config file. The daemon looks for .telora/daemon.json by default.
{
"teloraUrl": "https://your-telora-instance.supabase.co",
"organizationId": "your-organization-uuid",
"productId": "your-product-uuid",
"integrationBranch": "integration",
"maxTotalSessions": 5
}Configuration priority (highest to lowest):
- Environment variables
- Config file values
- Default values
Security note: The trackerId may live in ~/.telora/daemon.json (mode 0600, written by the connect flow) or in the TELORA_TRACKER_ID environment variable. Env vars take priority. The home-scoped daemon.json is the same posture as ~/.aws/credentials -- not committable.
Workstation tracking install model
Connect time, the daemon detects telora-ai (a Python CLI shipped under
scripts/) on PATH. If present, connect:
- Pre-populates the user's local tracking DB with the redeem-derived
credentials (
telora-ai config tracker_id ..., etc.) -- this skips the registration-code round-trip that Settings > AI Trackers normally requires - Merges
PostToolUseandUserPromptSubmithook entries into~/.claude/settings.jsonso a fresh Claude Code session is tracked end-to-end without manualtelora-ai setup-hooks
If telora-ai is absent, connect prints a remediation hint and
continues -- the daemon, MCP, and scaffolding parts of connect must
succeed even when tracking can't be wired automatically.
We picked detect-only (option c) over the alternatives:
- (a) pipx/uv install:
telora-aiis not on PyPI; no upstream install target exists yet. A pipx install of a path-shipped script doesn't generalise across machines that haven't checked out the repo. - (b) Single-binary build / fold into daemon: cleanest long-term but out of scope here; it requires either a PyInstaller pipeline that doesn't exist yet, or a TS rewrite of the tracking instrumentation.
The remediation hint points users at the documented bring-up so they can opt into tracking manually when they want it.
.mcp.json resolution model (option C)
The connect flow writes a credential-free .mcp.json so it can be committed and shared across collaborators:
{
"mcpServers": {
"telora-products": {
"command": "npx",
"args": ["-p", "@telora/mcp-products@latest", "telora-mcp-products"]
}
}
}The MCP server resolves credentials at startup in this order:
TELORA_TRACKER_ID+TELORA_URLenv vars (explicit override)~/.telora/daemon.json(written bytelora-daemon connect)
We picked option (c) -- read from daemon.json -- over the alternatives:
- (a) Export from shell rc: works only when the user's shell rc was sourced before
claudewas launched. Breaks under IDE-spawned Claude Code,.envrc-only setups, or any path where the rc didn't run. - (b) Sourced
~/.telora/env: same brittleness as (a), plus a new file we'd have to teach the user about. - (c) Read from
~/.telora/daemon.json: single source of truth, no shell-state coupling, same file the daemon already reads.
The trade-off: the MCP server has to do one filesystem read per startup. That's negligible compared to npx's cold-cache cost on the same path.
Available config file fields:
teloraUrl- Telora API URLorganizationId- Organization UUIDproductId- Product UUID (scopes daemon to one product; omit to handle all)repoPath- Repository pathworktreeDir- Worktree directoryintegrationBranch- Integration branch nameclaudeCodePath- Claude Code executable pathlogDir- Log directorymaxTotalSessions- Max concurrent agentssessionTimeoutMs- Session timeout in millisecondstokenLimit- Max tokens per sessioncostLimit- Max cost per session in dollars
How It Works
Focus Team Execution Model
- Focus polling: The daemon polls Telora every 30 seconds for active focuses with an assigned agent role and queued deliveries
- Filtering: Only picks up focuses for the configured
productId(if set) - Team spawning: For each ready focus, spawns a single Claude Code Agent Team (one team per focus)
- Task DAG: The team lead reads all deliveries and issues, builds a dependency graph respecting delivery priority and file overlap
- Parallel execution: Workers execute issues in parallel where safe (no file conflicts), sequentially where needed
- Delivery progression: As issues complete, deliveries advance through workflow stages (coding -> verify -> done)
- Merge on success: When all deliveries are complete, the focus branch is merged to integration
- Dynamic pickup: If new deliveries are added to the focus mid-execution, the team incorporates them automatically
Key daemon modules
focus-executor.ts- Focus team lifecycle (spawn, monitor, completion)task-dag-builder.ts- Pure function that builds dependency graphs from deliveries/issuesfocus-prompt-builder.ts- Builds the team lead's prompt with all contextdelivery-lifecycle.ts- Extracted guard evaluation, stage transition, git merge functionscompletion-handler.ts- Per-delivery completion (used by team lead for sub-delivery transitions)spawner.ts- Process spawning with Agent Teams mode always enabled
Multi-Repo Setup
To run agents on multiple repositories:
- Set
productIdin each daemon's.telora/daemon.json(orTELORA_PRODUCT_IDenv var) - Run one daemon per repository:
# Terminal 1 - Repo A (productId set in .telora/daemon.json)
cd /path/to/repo-a
telora-daemon run
# Terminal 2 - Repo B (productId set in .telora/daemon.json)
cd /path/to/repo-b
telora-daemon runEach daemon only picks up deliveries for the configured product.
Signals
SIGINT/SIGTERM: Graceful shutdown (waits for agents to checkpoint)SIGUSR1: Print status of running agents
Running in Production vs Development
For production use, always run the daemon with the compiled version:
# Global install (recommended -- enables self-update)
npm install -g @telora/daemon
telora-daemon run
# Or from source
cd packages/daemon
npm run build
npm startDo NOT use npm run dev (watch mode) when agents are running. The file watcher will restart the daemon whenever source files change, which kills any running agents and may leave sessions in a stuck "running" state.
If you need to modify daemon code while agents are working:
- Wait for agents to complete
- Or stop the daemon gracefully (Ctrl+C)
- Make your changes
- Restart the daemon
Requirements
- Node.js 20+
- Claude Code CLI (
claude) installed and authenticated - Git repository with write access
- Active Telora account with AI Work Tracker
License
MIT
