laneconductor
GitHub管理多项目开发的本地看板技能,通过Postgres和Vite仪表盘提供实时进度可视化。支持CLI和AI原生模式,处理任务跟踪、心跳同步及状态更新。
Trigger Scenarios
Install
npx skills add meller/laneconductor --skill laneconductor -g -y
SKILL.md
Frontmatter
{
"name": "laneconductor",
"parameters": [
{
"name": "command",
"options": [
"setup",
"activate",
"deactivate",
"start",
"stop",
"status",
"workflow",
"setup-deploy",
"deploy",
"qualityGate",
"quality-gate",
"move",
"pulse",
"newTrack",
"updateTrack",
"reportaBug",
"featureRequest",
"lock",
"unlock",
"plan",
"brainstorm",
"implement",
"review",
"remote-sync",
"comment",
"delete",
"revert",
"syncdb",
"init-tracks-summary"
],
"required": true,
"description": "The laneconductor command to execute"
},
{
"name": "subcommand",
"options": [
"scaffold",
"collection",
"generate",
"set"
],
"required": false,
"description": "Subcommand for setup and workflow operations"
},
{
"name": "track_number",
"required": false,
"description": "Track number (NNN format, e.g., 001, 042)"
},
{
"name": "lane",
"options": [
"backlog",
"ready",
"implement",
"review",
"done"
],
"required": false,
"description": "Kanban lane for move\/workflow operations (backlog, ready, implement, review, done)"
},
{
"name": "status",
"options": [
"queue",
"running",
"success",
"failed",
"blocked"
],
"required": false,
"description": "Status for pulse and move operations"
},
{
"name": "environment",
"options": [
"dev",
"staging",
"prod",
"production"
],
"required": false,
"description": "Deployment environment"
},
{
"name": "flags",
"options": [
"--sync-and-work",
"--source",
"--target"
],
"required": false,
"description": "Command flags and options"
}
],
"description": "Use this skill when the user invokes \/laneconductor commands. Manages multi-project development with a live Kanban dashboard backed by local Postgres. Handles setup, track management, heartbeat sync, and DB-backed status updates. Extends the conductor workflow with real-time visibility across all repository projects.",
"allowed-tools": "Read, Edit, Write, Bash, Glob, Grep",
"user-invocable": true
}
LaneConductor Skill
Sovereign Developer Environment — real-time visibility into AI-driven development across multiple repositories. Tracks progress through a local Postgres database and displays it on a Vite Kanban dashboard (port 8090).
Modes of Operation
- Full Local Stack (CLI-driven): Uses the
lcCLI, local Postgres, and a Vite Kanban dashboard. Best for solo developers wanting a rich UI. Requires Node.js and a Unix-like environment (Linux/macOS/WSL). - AI-Native / Skill-Only (Minimalist): No CLI or DB required. Simply copy this skill into your Claude Desktop, and the AI will manage everything through the filesystem (
conductor/folder). Perfect for Windows or lightweight environments.
Universal CLI (lc)
LaneConductor provides a global lc command to manage your projects without relying on an LLM or per-project Makefiles.
Installation
cd ~/Code/laneconductor
make install-cli
Core Commands
lc worker run <track>: Normally what you want. Runs a worker scoped to that track in the foreground and exits when it's done. It cannot claim any other queued track — unlikelc worker start --sync-and-work, which claims anything queued and will begin autonomous agent runs on every other track sitting inqueue. (Track 1109)lc worker start [--sync-and-work] [--only-tracks <n,n>] [--once]: Start the heartbeat worker in the background.--only-tracksrestricts what it may claim — it narrows only, and can never widen a server-side permission decision;--onceexits when that scoped work is finished. A second, independent gate sits alongside--only-tracksand the assignee gate: a track's own**Auto Run**marker (default no — see the marker table above) must also beyesbeforeautoLaunchLocalFs's auto-launch loop will pick it up from the queue.--only-tracksnaming a track does NOT bypassauto_run: false— it can only narrow further, never force a run; uselc worker run <track>for that. Like the assignee gate, this is bypassed for a track that's mid-conversation (waiting_for_reply: true), and never applies tolc worker run <track>or explicit dispatch (worker_dispatch), which are direct human/manager instructions, not auto-picking from the open queue. (Track 10017)lc worker stop: Stop the background heartbeat worker.lc worker restart: Restart the background heartbeat worker.lc worker status: Check the health and PID of the local worker.lc worker logs: Stream the worker's activity logs.lc worker sync: Manually trigger an immediate fan-out synchronization across all targets.lc status: Show a Kanban board of tracks in the terminal (with worker health check).lc ui [start|stop]: Manage the Vite dashboard.lc new "Title" "Description": Create a new track.lc setup: Initialize a new project with LaneConductor.lc add-target --url <url> [--key <key>] [--store-type gcp-secret] [--secret-name <name>]: Add a sync endpoint.lc add-target --type jira --domain <domain> --email <email> --project-key <key> [--token-env <env>]: Add a Jira sync target.lc add-target-mapping --lane <lc_lane> --target "<target_status>": Configure custom Jira status mapping for a specific Lane. (Example:lc add-target-mapping --lane implement --target "In Progress")lc list-targets: Show all sync targets and their active/disabled status.
Installation (one-time, per machine)
git clone <repo> ~/Code/laneconductor
cd ~/Code/laneconductor
make install # writes ~/.laneconductorrc (install path) + installs UI deps
To add LaneConductor to an existing project:
cd your-project
lc setup
The skill is symlinked from ~/Code/laneconductor/.claude/skills/laneconductor into each
project's .claude/skills/laneconductor. Updates to the laneconductor repo propagate
automatically to all projects — no re-installation needed.
Architecture
One repo, two parts:
laneconductor/— this LaneConductor AI skill (AI instructions + heartbeat worker)laneconductor/ui/— Vite dashboard athttp://localhost:8090
Shared local Postgres (laneconductor db) stores all project/track state. One project per repository. Zero cloud, zero auth.
[Your Project]
├── conductor/
│ ├── tracks/001-feature/
│ ├── index.md ← Atomic Status (Status, Progress, Title)
│ ├── plan.md ← Detailed Implementation Phases
│ └── spec.md ← Technical Requirements
├── tracks.md ← Project Summary (built from index.md files)
├── Makefile ← project build targets (lc commands handle LaneConductor)
└── .laneconductor.json ← DB config + project identity
[Postgres: laneconductor DB]
├── projects (one row per repo)
└── tracks (one row per track, per project)
[laneconductor/ui @ :8090]
├── Express API → localhost:8091
└── Vite + React → localhost:8090 (Kanban board, polls every 2s)
Protocol: conversation.md Format (required for sync)
Every entry appended to conductor/tracks/NNN-*/conversation.md — by an
agent or a human — MUST use this exact format, including continuation
lines:
> **author**: First line of the message
> second line, also prefixed with >
> third line
author is human, claude, gemini, or system. This is not just a
style convention: the sync worker's parser only recognizes lines matching
> **author**: ... (plus >-prefixed continuation lines) as comments to
push into the database. Anything else — markdown section headers, plain
blockquotes without an author marker, freeform prose — is silently not
synced. It stays in the file, but never reaches track_comments, so it
never shows up in the UI's Conversation tab, with no error or warning
anywhere (the sync worker does log a warning now when this happens, but
don't rely on that — get the format right the first time).
If you need to include long reference material as part of a turn — a
pasted email, contract text, a redline, negotiation history — wrap the
entire block under one > **author**: opening line, with every
subsequent line (including blank ones you want preserved, and any markdown
headers within the pasted content) still prefixed with >, so the parser
treats it all as one continuous comment body:
> **claude**: Liran replied with a full counter-redraft. Summary below.
>
> ## Liran's reply (received 2026-08-09)
>
> [full pasted text here, every line prefixed with >]
Do NOT drop the > **author**: prefix partway through just because the
content is long or reads more naturally as a standalone document — that is
exactly what silently breaks sync.
Protocol: Session Continuity (skip re-reading context on resume)
Every prompt you receive starts with a line the worker adds:
FRESH_SESSION: true
or
FRESH_SESSION: false
true means this is the first call in a new session for this (worker,
track) pair — proceed normally, including every "Load context" /
"Read existing context" step below. false means the worker resumed your
same Claude session from an earlier call on this same track (track
1086) — you already have product.md, tech-stack.md,
product-guidelines.md, design-language.md, spec.md, plan.md,
test.md, and conversation.md loaded from that earlier call in this
conversation. On FRESH_SESSION: false, skip re-reading any file you
already read earlier in this session — jump straight to the actual
instruction that follows. Re-reading them wastes the exact time/token cost
this mechanism exists to remove.
This does not mean skip reading everything unconditionally: if the
prompt is pointing you at something you genuinely haven't seen yet in this
session (a new human comment appended to conversation.md since your last
turn, a file that didn't exist before, output from a command you just
ran), still read it — "resumed" means "don't redo work you already did,"
not "ignore new information." Every "Load context" / "Read existing
context" step in the commands below is annotated with which files this
applies to.
Protocol: Locating Tracks
To find a track by number (e.g., "Track 017"):
- Run
lc track-dir <number>(Track 10040 REQ-15). This is the canonical resolver — the exact same decision logic the sync worker's own folder resolution runs (conductor/services/track-folder.mjs), so the skill and the worker can never disagree about which folder is real. It checksconductor/tracks-metadata.json's registration AND scansconductor/tracks/for both naming conventions (INITIALS-NNN-slugand legacyNNN-slug), resolves ambiguity the same way the worker does, and is read-only — it never renames a folder or writes metadata as a side effect of answering "where is this track". On success it prints the folder path (relative to the project root) to stdout and exits 0; on failure it exits non-zero with a diagnostic on stderr and prints nothing to stdout. Use--jsonfor{ folder, matches, registered }. - Fallback (no
lcon PATH — skill-only environments only): manually checkconductor/tracks-metadata.jsonfor the track number key'sfolder_path, then scanconductor/tracks/for a directory matching either convention —INITIALS-NNN-slug(e.g.AM-10023-my-feature) or the legacy bareNNN-slug. A scan that only checks the legacy bare-prefix pattern will silently miss every prefixed folder — this was a real, live bug (Finding 6, track 10040): it made the skill invisible to a track's own already-existing folder and caused it to scaffold a second, duplicate one. - Check
conductor/tracks.md: This summary file often contains links to the track folders. - Check
conductor/tracks/file_sync_queue.md: New tracks queued from the UI or CLI appear here with**Status**: pendingbefore the worker creates their folder.
Folder Naming Convention: conductor/tracks/INITIALS-NNN-slug/ for new tracks (e.g. AM-10023-my-feature). Legacy tracks use the old NNN-slug/ format and are fully supported.
🛑 A folder already existing for this track number, under EITHER convention, is not a
suggestion — scaffolding a second one is an error, not a fallback. Confirmed live on this exact
track (10040) during its own planning: a session that couldn't find its AM-10040-... folder via
the legacy-only scan scaffolded a duplicate 10040-... folder instead of using the real one. If
step 1 or step 2 above resolves ANY folder for this track number, use it — never create another.
Core Commands
/laneconductor setup
Initializes LaneConductor in the current project.
- Check for CLI: Check if
lcis available in the system (which lc). - If
lcis available: Tell the user they can runlc setupin their terminal for a guided wizard, or proceed here with/laneconductor setup scaffold. - If
lcis NOT available (Skill-Only Mode):- Assume
mode: "local-fs". - Create
.laneconductor.jsonwith minimal configuration:{ "mode": "local-fs", "project": { "name": "<detected-name>", "repo_path": "<absolute-path>", "primary": { "cli": "claude" } } } - Proceed immediately to
setup scaffold.
- Assume
Note: In Skill-Only mode, the AI acts as the primary orchestrator. There is no background heartbeat worker; instead, the AI updates the conductor/ files directly during its turn.
/laneconductor setup scaffold generate
File-generation phase of lc setup. The CLI wizard has already:
- Scanned the project (package.json, README, framework signals)
- Ran a multi-turn brainstorm loop where the user clarified the project
- Got explicit confirmation to proceed
Your job is only to generate the context files. Do not ask questions.
Read context from conductor/.setup-scaffold-context.json:
{
"project": { "name": "...", "git_remote": "...", "has_existing_code": true },
"scan": ["package.json: ...", "README: ...", "Framework signals: next.config.js"],
"brainstorm_summary": "user: ...\nassistant: ..."
}
If brainstorm_summary is present, use it as the authoritative source — it contains the agreed-upon understanding of the project. The scan snippets are supplementary.
Generate these files (create conductor/ dirs as needed):
conductor/product.md— what the product does, who uses it, key features, problem it solvesconductor/tech-stack.md— languages, frameworks, databases, infrastructure, key librariesconductor/workflow.md— commit strategy, branching, testing approach, code review processconductor/product-guidelines.md— brand/style/UX principles (stub with placeholders if unknown)conductor/design-language.md— color tokens (light/dark), typography scale, spacing system, component conventions, iconography/motion (stub with placeholders if unknown; see template below)conductor/deployment-stack.md— stub: "Not configured. Runlc setup-deploy."conductor/kpis.md— project north-star metrics (see KPI template below)conductor/user-stories.md— personas + their end-to-end journeys (see template below; stub with a TODO if no journey/flow language is found inbrainstorm_summary)conductor/quality-gate.md— the project's own verification commands (see template below). Must be tailored to THIS project's real stack — derive every command from what you actually found in the scan (package.jsonscripts, test runner, lint config, e2e framework), not from a generic list. A quality gate that names commands this project doesn't have is worse than none: it gets skipped or faked.conductor/tracks/andconductor/code_styleguides/— create dirs if missing.claude/MEMORY.md— create if not present
conductor/design-language.md template (infer from existing Tailwind/CSS-variable config,
component library theme, or design-token files if present; otherwise leave placeholders):
# Design Language
## Color Tokens
| Token | Light | Dark | Usage |
|-------|-------|------|-------|
| <e.g. background> | <hex/var> | <hex/var> | <context> |
## Typography Scale
- Font family: <family>
- Scale: <e.g. 12/14/16/20/24/32px, weight 400/500/600>
## Spacing System
- Base unit: <e.g. 4px>
- Scale: <e.g. 4/8/12/16/24/32/48>
## Component Conventions
- <e.g. buttons: rounded-md, primary/secondary/ghost variants>
- <e.g. cards: border + subtle shadow, no heavy elevation>
## Iconography / Motion
- <icon set / style>
- <motion: none / subtle / expressive — note any animation conventions>
conductor/kpis.md template (populate from brainstorm_summary if it contains goal/metric statements; otherwise use stubs):
# Project KPIs
## North-Star Metrics
| Metric | Target | Time Horizon | Status | Notes |
|--------|--------|--------------|--------|-------|
| <metric> | <target> | <e.g. Q2 2026> | tracking | <context> |
## Contributing Tracks
Tracks with `**Maps To**` referencing a metric above will appear here automatically.
conductor/quality-gate.md template. Replace every <...> with a real
command discovered in the scan; delete any line whose command this project
doesn't actually have rather than leaving an aspirational one. Note the
boxes are left unchecked and there is no pre-filled verdict — this
file is a checklist to run, not a report. (An earlier version of this
template shipped every box pre-ticked with Status: PASS already filled in,
which invited agents to rubber-stamp it; that is why this warning exists.)
# Quality Gate
> Checklist, not a report. Every box starts unchecked and is ticked only by
> whoever ran the command **this time** and saw it pass. Do not trust marks
> left by a previous run.
## Automated Checks
- [ ] Syntax/typecheck: `<e.g. npm run typecheck | node --check>` (Expected: no errors)
- [ ] Lint: `<e.g. npm run lint>` (Expected: clean)
- [ ] Unit + integration tests: `<e.g. npm test>` (Expected: all pass)
- [ ] Build: `<e.g. npm run build>` (Expected: succeeds)
- [ ] Coverage: `<e.g. npm run test:coverage>` (Expected: >= <N>% lines)
- [ ] Security: `<e.g. npm audit --audit-level=high>` (Expected: 0 high/critical)
## End-to-End / Real-Product Checks
> Required for any track touching UI or a user-facing flow. Unit tests
> cannot detect a feature that was never wired up.
- [ ] E2E suite: `<e.g. npx playwright test>` (Expected: all specs pass —
run the EXISTING specs; writing one trivial new passing test does not
satisfy this)
- [ ] Restarted long-running processes (workers, API server) before
verifying — they do not hot-reload, and testing against a stale
process is a false pass
- [ ] If no E2E suite exists: drove the flow manually and recorded the
observed user-visible result (screenshot, or real API/DB response)
## Manual Quality Review
- [ ] Architecture alignment: follows this project's established patterns
- [ ] Readability: clear naming, comments explain *why*
- [ ] No stubs in completed work: `grep -rniE "not yet implemented|TODO|FIXME|FFU" <src dirs>`
returns nothing in code paths marked `[x]`
## Verdict
- Status: <PENDING — set to PASS/FAIL only after running the above>
- Reviewer: <who/what ran it>
- Date: <ISO date of this run>
conductor/user-stories.md template (seed from brainstorm_summary if it describes concrete
user journeys/flows; otherwise stub with a TODO — don't invent personas that weren't discussed):
# User Stories
## <Persona A> — <short journey name>
**As a** <persona>, **I want to** <action>, **so that** <outcome>.
Flow: <ordered list of concrete steps — screens, emails, links, endpoints touched>
Related tracks: <[[track-name]] links, filled in as tracks implement/test pieces of this>
## <Persona B> — <short journey name>
...
Print progress as you write each file:
📝 Writing conductor/product.md... ✅
📝 Writing conductor/tech-stack.md... ✅
📝 Writing conductor/workflow.md... ✅
📝 Writing conductor/product-guidelines.md... ✅
📝 Writing conductor/design-language.md... ✅
📝 Writing conductor/deployment-stack.md... ✅
📝 Writing conductor/kpis.md... ✅
📝 Writing conductor/user-stories.md... ✅
📝 Writing conductor/quality-gate.md... ✅
Also symlink the skill and Antigravity workspace rule/skill (if not already linked):
SKILL_DIR=$(cat ~/.laneconductorrc 2>/dev/null || echo "$HOME/Code/laneconductor/.claude/skills/laneconductor")
TARGET=".claude/skills/laneconductor"
mkdir -p .claude/skills
ln -sf "$SKILL_DIR" "$TARGET"
# Symlink skill and rules for Antigravity
mkdir -p .agents/skills .agents/rules
ln -sf "$SKILL_DIR" ".agents/skills/laneconductor"
REPO_DIR=$(dirname $(dirname $(dirname "$SKILL_DIR")))
RULE_SRC="$REPO_DIR/.agents/rules/laneconductor.md"
ln -sf "$RULE_SRC" ".agents/rules/laneconductor.md"
After writing all files, check for foreign tracks and print summary.
/laneconductor setup scaffold
Generates the conductor/ folder structure and project context files using AI reasoning.
Use this only when invoked directly from an AI editor (not via lc setup).
Asks first:
"Does this project have existing code? (yes/no)"
Mode A — Existing code:
- Scan the codebase: read
package.json,README.md, source dirs, CI config, lint config - Auto-generate conductor context files from findings:
product.md— inferred from README, app name, entry points, routestech-stack.md— inferred frompackage.jsondeps, framework patterns, config filesdeployment-stack.md— stub: "Not configured. Runlc setup-deploy."workflow.md— inferred from.gitlog patterns, CI files, test setupproduct-guidelines.md— minimal template (hard to infer; leave stubs for user)design-language.md— inferred from existing Tailwind/CSS-variable config, component library theme (e.g. shadcn, MUI theme), or design-token files if present; otherwise minimal template likeproduct-guidelines.mdcode_styleguides/— inferred from.eslintrc,.prettierrc,tsconfig.jsonif presentuser-stories.md— only if concrete user journeys surface in the README/scan (e.g. distinct roles interacting with each other, invite/approval flows); otherwise stub with a TODO — don't fabricate personas from a codebase scan alone
- Ask one KPI question: "What does success look like? What are your 2–3 north-star metrics and rough targets?" — use answer to populate
kpis.md; if user skips, generate stub rows from README/product description inferences
Mode B — New project: Ask a short questionnaire:
- What does this project do? Who are the users?
- What language/framework/database will you use?
- TDD? Commit strategy? Branching model?
- Any brand/style standards?
- What does success look like? What are your 2–3 north-star metrics and rough targets? (e.g. "500 signups by Q2", "1000 DAUs", "HN front page")
- Any key user journeys worth tracking now? (optional — e.g. "admin invites a manager, manager invites a rep"; skip is fine,
user-stories.mdstubs if so)
Generate all conductor files with content from answers, including a stub for deployment-stack.md.
Both modes create:
conductor/
├── tracks/
├── code_styleguides/
├── product.md
├── product-guidelines.md
├── design-language.md
├── tech-stack.md
├── deployment-stack.md
├── user-stories.md
├── workflow.md
├── kpis.md
├── tracks.md
└── laneconductor.sync.mjs
Also:
-
Create
.claude/MEMORY.mdif not present -
Symlink the skill into this project so AI agents can invoke it locally:
SKILL_DIR=$(cat ~/.laneconductorrc 2>/dev/null || echo "$HOME/Code/laneconductor/.claude/skills/laneconductor") TARGET=".claude/skills/laneconductor" # Skip if this IS the laneconductor repo (skill is already the real file here) if [ "$(realpath $TARGET 2>/dev/null)" = "$(realpath $SKILL_DIR 2>/dev/null)" ]; then echo "ℹ️ Skill already present (this is the laneconductor repo)" else mkdir -p .claude/skills .agents/skills .agents/rules ln -sf "$SKILL_DIR" "$TARGET" ln -sf "$SKILL_DIR" ".agents/skills/laneconductor" REPO_DIR=$(dirname $(dirname $(dirname "$SKILL_DIR"))) ln -sf "$REPO_DIR/.agents/rules/laneconductor.md" ".agents/rules/laneconductor.md" echo "✅ Skill and rules symlinked for Claude and Antigravity" fiWindows/Manual Note: On Windows (without WSL), use
mklink /Dormklink /Jto create the symlink, or simply copy thelaneconductorskill folder from your installation path into.claude/skills/.This ensures that the latest version of the skill is always discoverable by the AI within this project.
The Heartbeat Worker (laneconductor.sync.mjs) is managed globally by the lc CLI. You no longer need a copy of this script inside your project's conductor/ folder. The lc start command will automatically use the canonical version from your LaneConductor installation.
Detect and import foreign tracks (from other conductor tools):
After creating the structure, scan conductor/tracks/ for folders that do NOT follow the NNN-slug naming convention (e.g. Gemini conductor tracks like feature_name_20260213/README.md). These won't be auto-synced by the heartbeat worker.
If foreign track folders are found, ask:
"Found N existing tracks from a previous conductor tool. Import them as LaneConductor tracks? (y/n)"
If yes, for each foreign folder:
- Parse the title from
README.mdorindex.md(first# Headingline) - Detect status from content: look for
✅ COMPLETED,DONE,complete→ lanedone;IN PROGRESS,in-progress→ laneimplement; anything else → lanebacklog - Assign the next available track number (continue from highest existing
NNN-*folder, or start at 001) - Create
conductor/tracks/NNN-slug/index.mdwith proper markers:# Track NNN: Title **Lane**: done **Lane Status**: success **Progress**: 100% **Last Run**: imported (n/a) **Summary**: Imported from previous conductor tool - Copy or symlink the original folder content alongside (or leave original README.md in place)
- Print:
✅ Imported NNN tracks → conductor/tracks/NNN-*/
The heartbeat worker will then pick them up via ignoreInitial: false on next lc start.
3. Environment Verification & Self-Healing: After scaffolding files, you MUST verify the project environment:
- Check Dependencies: Verify if
chokidaris installed (npm list chokidaror checkingpackage.json). - Check Git: Verify
git rev-parse --is-inside-work-treeand detect current branch naming (e.g.,mainvsmaster). - Check Binaries: Verify that the agents configured in
.laneconductor.json(e.g.,claude,agy,gemini) are accessible in the systemPATH.
If issues are found:
- Report them clearly:
⚠️ Environment Issue: <detailed description>. - Ask:
Would you like me to create Track 001 to track these environment fixes? (y/n). - If yes, create
conductor/tracks/001-fix-environment/index.md:# Track 001: Fix Project Environment **Lane**: backlog **Lane Status**: queue **Progress**: 0% **Summary**: Initial environment verification found missing dependencies or configuration gaps. - Write specific tasks to
conductor/tracks/001-fix-environment/plan.md(e.g.,npm install chokidar,git init, etc.).
Create conductor/quality-gate.md if enabled:
If create_quality_gate is true in .laneconductor.json, create conductor/quality-gate.md with quality standards (Unit Tests, Linting, Build, Security).
Do NOT embed the sync.mjs code inline in this skill — the canonical source at
~/Code/laneconductor/conductor/laneconductor.sync.mjs is always correct and avoids
template substitution issues with parameterized query placeholders.
workflow.md template (human-readable docs only — machine config lives in workflow.json):
# Workflow
## Commit Strategy
- Conventional Commits: feat/fix/docs/refactor/test/chore
- Include track number: `feat(track-001): description`
## Branching Model
- main: production-ready
- feature branches: track-NNN-description
## Development Process
1. Create track with `/laneconductor newTrack`
2. Write spec.md before coding
3. Implement in phases with commits per phase
4. Update progress with `/laneconductor pulse`
## Code Review
- Self-review before marking done
- Update plan.md with learnings after each phase
## Workflow Configuration
Machine-readable config lives in `conductor/workflow.json`.
Edit it directly or via `/laneconductor workflow set`.
See `conductor/workflow.json` for lane transitions, parallel limits, and model overrides.
Also create conductor/workflow.json during scaffold (copy from the canonical laneconductor repo):
SKILL_DIR=$(cat ~/.laneconductorrc 2>/dev/null || echo "$HOME/Code/laneconductor/.claude/skills/laneconductor")
LC_REPO=$(dirname $(dirname $(dirname "$SKILL_DIR")))
cp "$LC_REPO/conductor/workflow.json" conductor/workflow.json
echo "✅ workflow.json copied from canonical source"
/laneconductor setup collection
Sets up the collection destination — configures the operating mode, AI agents, and registers this project.
-
Operating mode — ask first, as it determines what infrastructure is needed:
How will this worker operate? [1] local-fs — no DB, no API; pure filesystem (offline, CI, testing) ← default [2] local-api — local Postgres + local Collector at localhost:8091 + Vite UI at localhost:8090 [3] remote-api — remote Collector (laneconductor.io or self-hosted)Write
"mode": "<choice>"into.laneconductor.json. This is the first field — it controls everything below.Mode Needs DB? Needs Collector? UI Dashboard Best for local-fsNo No No Offline, CI, testing local-apiYes (local) Yes ( :8091)localhost:8090(Vite Kanban)Solo dev full stack remote-apiNo (remote) Yes (remote) Cloud URL Teams, multi-machine If
[1] local-fs: skip steps 2–3 (no DB or collector needed). Jump straight to step 4 (agent config). -
DB connection (local-api only — skip for local-fs and remote-api) Show current values if
.laneconductor.jsonalready exists:DB host [localhost]:DB name [laneconductor]:DB port [5432]:DB user [postgres]:DB password [postgres]:← stored in.envasDB_PASSWORD, NOT in.laneconductor.jsonDB SSL? (y/n) [n]:
-
Collectors — ask how this project syncs data (skip for local-fs):
Which collectors? [1] Local only — local Postgres + local collector (default, works today) [2] LC cloud — laneconductor.io managed (paste token) [3] Both — local primary + LC cloud fire-and-forgetIf
[2]or[3], collect the LC cloud token:LC Cloud Token (lc_xxxx...):← stored in.envasCOLLECTOR_n_TOKEN, NOT in config.Store Type:[1].env(direct token) [2]gcp-secret(dynamic GCP Secret Manager resolution).- If
gcp-secret, ask for:Secret Name (e.g., LC_PROD_KEY). - The default URL for LC cloud is
https://app.laneconductor.com.
Write all configurations to
.laneconductor.jsonand tokens to.env(if using token storage). Ensure.gitignoreexists and contains.env. -
Primary agent — ask which CLI drives this project (
claude/antigravity (agy)/gemini (retired)/other). Then: a. Verify reachability by running the version check:Agent Check command Passes if claude claude --versionexits 0, prints version antigravity/agy agy --versionexits 0, prints version gemini (retired) npx @google/gemini-cli --versionexits 0, prints version other ask for CLI command, then run it exits 0 On success: print
✅ <agent> reachable — <version>On failure: warn, askContinue anyway? [y/N]:— abort if N. Ifgeminiis chosen: additionally warn that Gemini CLI was retired by Google and antigravity is now recommended (seebin/lc.mjs's setup wizard for the exact wording) — non-blocking, setup still proceeds if the user continues anyway.b. Discover models dynamically — do NOT present a hardcoded list (except for Claude). For Claude, the CLI uses aliases. Do not run a discovery command. Instead, recommend:
haiku: Claude 3.5 Haikusonnet: Claude 3.7 Sonnet- Leave blank/default for system recommendation.
For others, run a one-shot prompt to get current models:
Agent Discovery command antigravity/agy no known non-interactive model-listing command yet — ask user: Model name (leave blank to set later):gemini (retired) npx @google/gemini-cli -p "List the available Gemini model IDs as a plain newline-separated list, no commentary"other ask user: Model name (leave blank to set later):Parse the output and present the discovered model IDs as choices. If discovery fails or times out (>15s), fall back to asking the user to type a model name. Always allow free-text entry as a fallback.
c. Ask:
Primary model [default]:(emphasize that blank = best default) -
Secondary agent (optional) — ask
Add a secondary AI CLI? (none / claude / antigravity / gemini (retired) / other). If notnone: repeat reachability check + model discovery for that CLI. Ask:Secondary model [default]:(emphasize that blank = best default) -
Detect project name: run
git remote get-url origin 2>/dev/nulland parse the repo name. Fall back tobasename $(pwd). -
Write
.laneconductor.json(passwords NEVER go here — they live in.env):
Mode 1 — local-fs (minimal, no infrastructure):
{
"mode": "local-fs",
"project": {
"name": "<detected-name>",
"repo_path": "<absolute-path>",
"git_remote": "<git-remote-or-null>",
"primary": { "cli": "claude", "model": "<selected-model>" }
},
"collectors": []
}
Mode 2 — local-api (full local stack):
{
"mode": "local-api",
"project": {
"name": "<detected-name>",
"id": null,
"repo_path": "<absolute-path>",
"git_remote": "<git-remote-or-null>",
"primary": { "cli": "claude", "model": "<selected-model>" },
"secondary": { "cli": "agy", "model": "<selected-model>" },
"dev": { "command": "npm run dev", "url": "http://localhost:3000" }
},
"collectors": [{ "url": "http://localhost:8091", "token": null }],
"ui": { "port": 8090 }
}
Mode 3 — remote-api (cloud or self-hosted):
{
"mode": "remote-api",
"project": {
"name": "<detected-name>",
"id": null,
"repo_path": "<absolute-path>",
"git_remote": "<git-remote-or-null>",
"create_quality_gate": false,
"primary": { "cli": "claude", "model": "<selected-model>" }
},
"collectors": [{ "url": "https://collector.laneconductor.io", "token": null }],
"ui": { "port": 8090 }
}
Omit id for local-fs (no DB row). Omit secondary if no secondary agent was chosen. Omit dev if dev server quick-start is not needed. Token secrets are stored in .env as COLLECTOR_0_TOKEN / COLLECTOR_1_TOKEN (mapped by array index) — never in the JSON.
Dev Server Config (Optional):
dev.command— Shell command to start the dev server (e.g.,npm run dev,cargo run)dev.url— URL where the dev server runs (e.g.,http://localhost:3000) When configured, the Kanban UI will show a "Start Dev Server" button on tracks in the review and in-progress lanes. Reviewers can launch the running app without switching to a terminal. Omit thedevkey entirely if dev server quick-start is not needed for this project.
- Create the DB schema (local-api only — skip for local-fs and remote-api)
Run via
psqlif available, else write + run a one-time node script:
CREATE TABLE IF NOT EXISTS projects (
id SERIAL PRIMARY KEY,
name TEXT NOT NULL,
repo_path TEXT UNIQUE NOT NULL,
git_remote TEXT,
git_global_id UUID UNIQUE,
primary_cli TEXT DEFAULT 'claude',
primary_model TEXT,
secondary_cli TEXT,
secondary_model TEXT,
create_quality_gate BOOLEAN DEFAULT false,
created_at TIMESTAMP DEFAULT NOW()
);
CREATE TABLE IF NOT EXISTS tracks (
id SERIAL PRIMARY KEY,
project_id INTEGER REFERENCES projects(id) ON DELETE CASCADE,
track_number TEXT NOT NULL,
title TEXT NOT NULL,
lane_status TEXT DEFAULT 'planning', -- planning|backlog|in-progress|review|done
lane_action_status TEXT DEFAULT 'waiting', -- waiting|running|done
lane_action_result TEXT, -- success|error|timeout
progress_percent INTEGER DEFAULT 0,
current_phase TEXT,
content_summary TEXT,
sync_status TEXT DEFAULT 'synced',
last_updated_by TEXT DEFAULT 'worker',
last_heartbeat TIMESTAMP DEFAULT NOW(),
created_at TIMESTAMP DEFAULT NOW(),
UNIQUE(project_id, track_number)
);
Lane Action State Machine & Dynamic Boundaries
Transitions are NOT hardcoded. You MUST read conductor/workflow.json at the start of every command to determine the correct target lanes for success and failure.
🛑 CRITICAL: Boundary Rules
/laneconductor plan: ONLY produces documentation. NEVER write application code. On completion, set**Lane**to the value oflanes.plan.on_successfromworkflow.json./laneconductor implement: ONLY executes theplan.md. On completion, set**Lane**to the value oflanes.implement.on_successfromworkflow.json./laneconductor review: ONLY evaluates code. NEVER fix bugs. On success/failure, set**Lane**to the target specified inlanes.review(on_successoron_failure)./laneconductor quality-gate: Final verification. On completion, set**Lane**to the value oflanes.quality-gate.on_successfromworkflow.json(done:queue— quality-gate never setsdone:successdirectly; that is the merge action's job)./laneconductor merge: ONLY merges/opens a PR for already-reviewed, already-gated code. NEVER write feature code or fix bugs beyond what's needed to resolve a merge conflict. Runs in the primary checkout (workspace: main), never in the track's worktree. On a clean direct-mode merge or a merged PR, sets**Lane Status**: success(meaningdone:success— actually shipped). On pr-mode push, sets**Lane Status**: waiting. On an unresolvable conflict, sets**Lane Status**to the value oflanes.done.on_failurefromworkflow.json.
🛑 BOUNDARY ENFORCEMENT: Never override the workflow. Use workflow.json as the sole authority for target lanes. Do NOT assume implement always follows plan; the project may be configured with a review lane in between.
# psql approach:
psql -h <host> -p <port> -U <user> -d <dbname> -f /tmp/laneconductor_schema.sql
/laneconductor activate (or start) [--sync-and-work]
Start the heartbeat worker.
- Verify
.laneconductor.jsonexists — if not, tell user to runsetup collectionfirst - Check
.sync.pid— warn if process already running - Start:
node bin/lc.mjs worker start [--sync-only]
By default, the worker will only perform file↔API synchronization and will NOT poll the database for queued tracks to execute. If --sync-and-work is provided, it will also poll and execute tracks from the queue.
Print:
✅ LaneConductor heartbeat started (PID: XXXX) [SYNC-ONLY mode] or [SYNC-AND-WORK mode]
📊 Dashboard: http://localhost:8090
/laneconductor deactivate (or stop)
Stop the heartbeat worker.
PID=$(cat conductor/.sync.pid 2>/dev/null)
if [ -n "$PID" ]; then
kill "$PID" && echo "✅ Heartbeat stopped" && rm conductor/.sync.pid
else
echo "⚠️ No heartbeat running"
fi
Print reminder to also stop the Vite UI (Ctrl+C in the UI terminal).
/laneconductor status
Display a Kanban board of all tracks in the terminal. Mode-aware: intelligently chooses between filesystem and database.
Logic:
- Read
.laneconductor.jsonto detect operating mode - If
mode: "local-fs"(no database):- Scan
conductor/tracks/*/index.md - Extract:
track_number,title,**Lane**,**Progress**,**Phase**markers - Display Kanban grouped by lane (source of truth from filesystem)
- Scan
- If
mode: "local-api"or"remote-api"(has database):- Query Postgres:
SELECT track_number, title, lane_status, progress_percent, current_phase, last_heartbeat FROM tracks WHERE project_id = :project_id ORDER BY track_number - Display Kanban grouped by lane (real-time from DB + UI state)
- Query Postgres:
- Print grouped by lane with progress and activity indicators:
╔══════════════════════════════════════════════════════════════════╗
║ Project: my-app │ 2026-02-23 14:32 [local-fs] ║
╠══════════╦════════════════╦═════════════╦═══════════════════════╣
║ BACKLOG ║ IN PROGRESS ║ REVIEW ║ DONE ║
╠══════════╬════════════════╬═════════════╬═══════════════════════╣
║ 003-auth ║ 001-dashboard ║ 002-api ║ 004-docs ║
║ 005-logs ║ 45% ⏳ ║ 90% ⚠️ ║ (100%) ║
╚══════════╩════════════════╩═════════════╩═══════════════════════╝
Indicators:
⏳= in-progress track (shows "Xs ago" if DB available)⚠️= has gaps/warnings from review(100%)= done tracks- Mode indicator shown in header:
[local-fs],[local-api], or[remote-api]
/laneconductor workflow
Display the current workflow configuration from conductor/workflow.json as a formatted table.
- Read
conductor/workflow.json - Display:
╔══════════════════════════════════════════════════════════════════════╗
║ Workflow: <project> │ Global parallel limit: 3 ║
║ Default model: haiku │ Default retries: 1 ║
╠══════════════╦═══════════════╦══════════════╦════════════════════════╣
║ LANE ║ AUTO ACTION ║ ON SUCCESS ║ ON FAILURE ║
╠══════════════╬═══════════════╬══════════════╬════════════════════════╣
║ planning ║ plan ║ planning ║ backlog ║
║ in-progress ║ implement ║ review ║ in-progress ║
║ review ║ review ║ quality-gate ║ in-progress ║
║ quality-gate ║ qualityGate ║ done ║ planning ║
╚══════════════╩═══════════════╩══════════════╩════════════════════════╝
/laneconductor workflow set [lane] [key] [value]
Update a single field in conductor/workflow.json.
Examples:
/laneconductor workflow set review max_retries 3
/laneconductor workflow set quality-gate on_failure review
/laneconductor workflow set in-progress primary_model sonnet
/laneconductor workflow set global total_parallel_limit 5
Logic:
- Read
conductor/workflow.json - Navigate to
lanes[lane][key](orglobal[key]/defaults[key]if lane isglobal/defaults) - Update the value (parse integers for numeric fields)
- Write back to
conductor/workflow.json - Print:
✅ workflow.json updated: lanes.<lane>.<key> = <value>
Valid keys per lane: parallel_limit, max_retries, primary_model, auto_action, on_success, on_failure
Valid on_success/on_failure values: planning, backlog, in-progress, review, quality-gate, done, null
/laneconductor setup-deploy generate
File-generation phase of lc setup-deploy. The CLI wizard (lc setup-deploy) has already:
- Scanned for deployment signals
- Asked the user all questions interactively
- Verified credentials
- Got explicit user confirmation
Your job is only to generate the files. Do not ask questions. Do not scan. Do not show a confirmation prompt. Just write the files.
Read context from conductor/.setup-deploy-context.json:
{
"components": { "frontend": "...", "backend": "...", "db": "...", "secrets": "..." },
"environments": ["prod", "staging"],
"deploy_command": "bash infra/deploy.sh",
"cicd": false,
"credentials": { "gcp": "verified (user@example.com)", "firebase": "verified" },
"existing_signals": ["deploy.sh", "Dockerfile", "firebase.json"],
"files_to_create": ["conductor/deployment-stack.md", "conductor/deploy.json", ".env.example"],
"brainstorm_summary": "user: ...\nassistant: ..."
}
If brainstorm_summary is present, use it as the authoritative source for the final configuration — it contains the agreed-upon decisions from the interactive brainstorm. The components fields may contain raw user input (including questions); the brainstorm summary has the clarified answers.
Generate each file listed in files_to_create:
Print progress as you write each file:
📝 Writing conductor/deployment-stack.md... ✅
📝 Writing conductor/deploy.json... ✅
📝 Writing .env.example... ✅
🔒 Updating .gitignore... ✅
conductor/deployment-stack.md — Full human-readable topology:
# Deployment Stack
## Provider
[derived from components]
## Environments
[list each environment with region/project if detectable]
## Services
- Frontend: [component]
- Backend: [component]
- Database: [component]
- Secrets: [component]
## Authentication
[credentials entry from context — verified ✅ or NOT CONFIGURED]
## Deploy Command
lc deploy prod → [deploy_command] prod
conductor/deploy.json — Machine-readable config:
{
"environments": {
"prod": { "command": "[deploy_command] prod" },
"staging": { "command": "[deploy_command] staging" }
},
"components": { "frontend": "...", "backend": "...", "db": "...", "secrets": "..." },
"secrets": {
"strategy": "[derive from secrets component]",
"keys": []
},
"ci": null
}
Set "ci": null unless cicd is true in context (in which case add CI config block).
.env.example — Required CI env var names only, never actual values:
- GCP:
GOOGLE_APPLICATION_CREDENTIALS,GCP_PROJECT,GCP_REGION - Firebase:
FIREBASE_TOKEN(for CI; locally use ADC) - Vercel:
VERCEL_TOKEN,VERCEL_ORG_ID,VERCEL_PROJECT_ID - AWS:
AWS_ACCESS_KEY_ID,AWS_SECRET_ACCESS_KEY,AWS_REGION - Supabase:
SUPABASE_ACCESS_TOKEN,SUPABASE_PROJECT_REFInclude only providers relevant to the selected components.
.gitignore — Append if not already present:
.env
*.tfvars
*-key.json
service-account*.json
.vercel
After writing all files, print:
✅ Deployment stack configured!
Run: lc deploy prod
Run: lc deploy staging
And list any credentials marked NOT CONFIGURED with their setup commands.
Example deploy.json Schema:
{
"environments": {
"prod": { "command": "bash infra/deploy.sh prod", "project": "my-project-prod" },
"staging": { "command": "bash infra/deploy.sh staging", "project": "my-project-staging" }
},
"components": { "frontend": "Firebase Hosting", "backend": "GCP Cloud Run", "db": "Cloud SQL", "secrets": "GCP Secret Manager" },
"secrets": { "strategy": "adc+secret-manager", "keys": [] },
"ci": null
}
/laneconductor deploy [env]
Execute the deployment command for the specified environment.
Logic:
- Read
conductor/deploy.json. - Locate the command for the requested
env(default:prod). - Execute the command in the terminal with
stdio: inherit. - Log the output to
conductor/logs/deploy-<env>-<timestamp>.log.
The Filesystem-as-API Interface
The Skill Worker communicates state to the dashboard by writing specific bold markers in index.md or plan.md. The Sync Worker parses these markers and updates the database via the API.
| Marker | API Field | Purpose |
|---|---|---|
**Status**: [lane] |
lane_status |
Moves the card on the Kanban board (e.g., in-progress, review). |
**Step**: [step] |
phase_step |
Describes the current activity (e.g., planning, coding, complete). |
**Progress**: [0-100]% |
progress_percent |
Sets the track's completion percentage. |
**Phase**: [text] |
current_phase |
Names the current phase being worked on. |
**Summary**: [text] |
content_summary |
A one-line summary of the current work/problem. |
**Waiting for reply**: [yes|no] |
waiting_for_reply |
Signals that a human comment needs an answer. |
**Workspace**: [main|branch] |
workspace_mode |
Track 1115: deliberate, human-set override — main runs lane actions directly in the primary checkout (no worktree, no track branch); branch is today's default. Set by a human, lc new --workspace, or a track detail panel control — never written by an inference (see **Track Kind** below for that). Always wins over the auto-derived default, but the plan lane itself always runs main regardless of this marker, and an auto-queue claim still forces branch when nothing set this marker explicitly. |
**Track Kind**: [bug|feature] |
(none — narrow, worker-internal) | Track 1115: records the New Track modal's bug/feature classification, or /laneconductor plan's own classification when creation didn't provide one. Feeds the type-derived workspace default (bug → main) WITHOUT becoming an unconditional override the way **Workspace** is — this is what lets an auto-queue claim still fall back to branch for an inferred-but-never-confirmed bug track. Not a general track classification; nothing else should read it. |
**Auto Run**: [yes|no] |
auto_run |
Whether a non-sync-only worker's auto-launch loop may claim this track from the queue. Default no — absent marker means not auto-picked (track 10017). |
**Merge Mode**: [direct|pr] |
merge_mode |
Track 10035: how the done-lane merge action integrates the branch. direct merges straight to main in-session; pr pushes the branch and opens a GitHub PR, landing at done:waiting. Default pr. Settable at creation (lc new --merge-mode) or by hand; the file marker is authoritative over the DB's tracks.merge_mode column — the migration sweep corrects any DB value that disagrees with it. |
**PR URL**: [url] |
pr_url |
Track 10035: the GitHub PR link written by the merge action in pr-mode, once gh pr create returns. This is the completion affordance shown on both the Kanban card and the Worktrees row while the track sits at done:waiting. |
Completion Comment Convention
Every terminal lane-action outcome (plan, implement, review, quality-gate, merge) appends
exactly one structured comment to conversation.md on completion, always authored system
and always leading with one of these three emoji as the very first character of the body (the
Inbox's classification matches on this leading character — see /api/inbox):
| Emoji | Meaning | Inbox bucket |
|---|---|---|
✅ |
Success — no action needed, informational only | Recent activity |
⚠️ |
Needs intervention — human should look at this | Needs your input |
❌ |
Failed | Needs your input |
Format: > **system**: <emoji> <one-line summary>. — e.g.
> **system**: ✅ Plan complete — moved to implement. Don't double-post: if an earlier step in
the same run already posted a ⚠️/❌ comment for this outcome (e.g. the fundamentals-conflict
guardrail, or a quality-gate FAIL), that comment satisfies this convention on its own — no need
for a second one.
/laneconductor qualityGate [track_number]
Verifies the implementation of a track against the project's quality standards. This command is usually invoked automatically by the worker when a track enters the quality-gate lane.
Logic:
- Read
conductor/quality-gate.mdto understand the criteria. - Perform automated checks based on the criteria:
- Syntax: Run linter or
node --checkon modified files. - Existence: Verify all files listed in
plan.mdphases actually exist. - Configuration: Ensure
.laneconductor.jsonand.envare valid. - Reachability: Try to invoke any new commands or APIs introduced.
- Automated Tests: Run the project's test suite (e.g.,
npm test). - Coverage: Verify if test coverage meets the required target (default 50%).
- Syntax: Run linter or
- Outcome:
- PASS: Move track to
donelane, updateindex.mdstatus tosuccess. - FAIL: Move track back to
implement:queue, list failures inindex.mdsummary for the next implementation round.
- PASS: Move track to
/laneconductor move [track-number] [lane:status]
Move a track to a different lane and optionally set its status (defaults to queue if moving lane).
Usage:
/laneconductor move NNN backlog(Moves to backlog, status queue)/laneconductor move NNN implement:queue(Moves to implement, triggers auto-action)/laneconductor move NNN plan:success(Moves to plan, marks as done)
/laneconductor pulse [track-number] [status] [progress%] [summary?]
Update the track status and progress by modifying its Markdown files.
Logic:
- Find
conductor/tracks/NNN-*/index.md. - Update the following markers:
**Status**: [status]**Step**: [step](infer from context if not provided)**Progress**: [progress]%**Summary**: [summary](or update the Problem/Solution section)**Waiting for reply**: no(Always set tonoafter an AI response)
- The Sync Worker will detect these changes and update the DB.
/laneconductor newTrack [name] [description]
Registers a new track in the file sync queue. The sync worker processes it on next heartbeat.
- Determine the next track number AND derive author initials:
- Run
git config user.nameandgit config user.emailto get author info. - Derive initials: uppercase first letter of each word, max 3 chars, fallback to
XXif not configured. Examples: "Asaf Meller" →AM, "John von Neumann" →JVN, "Madonna" →M. - Find the highest existing number by scanning
conductor/tracks/file_sync_queue.md(matching### Track NNN:) and allconductor/tracks/*/folder names — extract the number regardless of prefix (e.g. both10022-slugandAM-10022-slugcontribute10022). - The display ID is
INITIALS-NNN(e.g.AM-10023). The folder name isINITIALS-NNN-slug/.
- Run
- Create
conductor/tracks/INITIALS-NNN-slug/index.mdimmediately (for fast feedback):
Default# Track INITIALS-NNN: [name] **Lane**: plan **Lane Status**: queue **Progress**: 0% **Phase**: New **Type**: [dev|marketing|sales|support|other] **Merge Mode**: [direct|pr] ← only if specified at creation (track 10035 REQ-12) **Auto Run**: [yes|no] ← only if specified at creation (track 10035 REQ-12) **Author**: INITIALS **Created By**: user@email.com **Summary**: [description]**Type**todevunless the user specified a type.**Merge Mode**and**Auto Run**are sparse-emission, same convention as**Workspace**— omit the line entirely unless the user explicitly asked for one at creation (e.g. "make this direct-mode and auto-runnable"); an absent marker falls through to each field's own documented default (prfor merge mode, not-auto-run for Auto Run) via the normal resolution the worker already applies everywhere else. The CLI equivalent islc new "Title" "Description" --merge-mode direct|pr --auto-run yes|no. - Append a typed entry to
conductor/tracks/file_sync_queue.md(under## Track Creation Requests):### Track NNN: [name] **Status**: pending **Type**: track-create **Created**: [ISO timestamp] **Title**: [name] **Description**: [description] **Author**: INITIALS **Metadata**: { "priority": "medium", "assignee": null } - The sync worker detects the change (via chokidar or 5s heartbeat), creates the DB row, and moves the entry to
## Completed Queue. - Skill check for non-dev types: if type is
marketingorsales, check.claude/skills/for recommended skills:- Marketing:
social-content,copywriting,content-strategy,launch-strategy - Sales:
sales-enablement,cold-email - Print
⚠️ Track type 'marketing' works best with [skill] — not found in .claude/skills/for each missing skill. - Print
✅ [skill] availablefor each present skill.
- Marketing:
- Print:
✅ Track NNN queued in file_sync_queue.md. Worker will register in DB on next cycle.
/laneconductor lock [track-number]
Acquire a git lock and create an isolated worktree for safe parallel execution. Returns the worktree_path for the skill to use.
Usage:
const { worktree_path } = await /laneconductor lock NNN
process.chdir(worktree_path)
// ... do work ...
await /laneconductor unlock NNN
/laneconductor unlock [track-number]
Release a git lock and clean up the worktree created by the lock command. Always call this in a finally block to ensure cleanup.
Usage:
try {
const { worktree_path } = await /laneconductor lock NNN
process.chdir(worktree_path)
// ... do work ...
} finally {
await /laneconductor unlock NNN
}
/laneconductor plan [track-number]
Scaffold or refine the planning phase of a track (Spec + Plan).
- Claim the track immediately — before any other work, write
**Lane**: planand**Lane Status**: runningtoconductor/tracks/NNN-*/index.md. Setting**Lane**explicitly (not just**Lane Status**) matters whenever this command is invoked directly rather than via the normal queued-worker path — e.g. a KPI-miss replan or a manual re-run — where the track may not already be sitting in theplanlane; without it the Kanban board shows the track running in the wrong column for the whole duration of the work. This prevents the worker from double-launching and shows activity in the UI. 0b. Workspace classification (Track 1115) — ifindex.mdhas neither a**Workspace**marker nor a**Track Kind**marker, classify the track asbugorfeaturefrom its title, description, andconversation.md, plus a quick scan of the codebase area it touches. Write**Track Kind**: bugor**Track Kind**: featuretoindex.md— not**Workspace**directly. This distinction matters: theplanlane runs before every other lane action (see step 7's transition andconductor/workflow.md's Workspace Modes section), so if this step wrote**Workspace**directly, the inference would become indistinguishable from a deliberate human override for nearly every track that reaches plan without one already set — silently defeating the auto-queue safety check that keeps an inferred bug classification from running unattended on main.**Track Kind**only feeds the type-derived default; it does not override anything on its own. Append the classification and its reasoning toconversation.mdin the required format:> **system**: Classified as **Track Kind**: <bug|feature> — <one-line reasoning>.A wrong guess is visible and overridable this way, never silent. Skip this step entirely if either marker is already present (an explicit**Workspace**always takes precedence and needs no classification). - Locate the Track: Use the Protocol: Locating Tracks — run
lc track-dir <number>first. If it resolves a folder (exit 0, any naming convention), that folder is the track — go to Refine, never Scaffold, regardless of whatfile_sync_queue.mdsays. If it exits non-zero (no folder exists anywhere) AND the track has**Status**: pendinginfile_sync_queue.md, proceed to Scaffold. - Scaffold (only if
lc track-dirfound nothing — REQ-15):- 🛑 Scaffolding over an existing track number is an error, not a fallback. This step may
only run after step 1's resolver genuinely found nothing under any convention. Confirmed
live (Finding 6, track 10040): an earlier version of this instruction said to scaffold at
the legacy
NNN-slug/path unconditionally, which created a duplicate folder beside a track's real, already-existingINITIALS-NNN-slug/one every time the resolution step missed it. - Create directory
conductor/tracks/INITIALS-NNN-slug/— the current documented convention (see Protocol: Locating Tracks's Folder Naming Convention), never the bare legacyNNN-slug/form for a new track. DeriveINITIALSthe same way/laneconductor newTrackdoes (uppercase first letter of each word ingit config user.name, max 3 chars). - Create
index.md(Title, Lane, Status: planning, Progress: 0%, Last Run: user) - Create
spec.md(Problem, Requirements, Acceptance Criteria, Data Model Changes (if applicable)) - Create
plan.md(Phases, Tasks with ⏳) - Create
test.md(Test Commands, Test Cases per phase, Acceptance Criteria checklist) - In
file_sync_queue.md: update the entry's**Status**: pending→**Status**: processed.
- 🛑 Scaffolding over an existing track number is an error, not a fallback. This step may
only run after step 1's resolver genuinely found nothing under any convention. Confirmed
live (Finding 6, track 10040): an earlier version of this instruction said to scaffold at
the legacy
- Refine (if exists):
- Read existing
spec.md,plan.md, andtest.md(skip ifFRESH_SESSION: falseand you already read them earlier this session — see Protocol: Session Continuity — e.g. a replan immediately following a brainstorm on the same session). - Check for human comments in
conversation.md(always re-read this one). Ifconversation.mdcontains a brainstorm thread (lines starting with> **system**: Brainstorm), treat the Q&A dialogue as enriched requirements — incorporate answers intospec.md,plan.md, andtest.mdbefore finalising. - Flesh out missing requirements or phase details based on current codebase context.
- Fulfill test.md: If
test.mdis missing, empty, or contains the generic(Test cases to be added)stub, you MUST fully scaffold/rewrite it using the Track File Templates format at the bottom of this file. Populatingtest.mdwith specific, real test cases for each phase inplan.mdis a MANDATORY requirement of the planning phase. Never leave the test file empty or at the generic stub. - Acceptance criteria must describe the user-facing outcome, never the scaffolding. Every criterion has to be something a user could observe. Criteria that lock in a placeholder are forbidden — e.g. "the worker logs the expected 'not yet implemented' message", "no real code path is exercised", "the dispatch is marked failed with that message". Those are satisfied by a stub, so the track can pass its own gate while the feature does not exist (this happened — see the quality-gate command's done-gate). Write "a worker actually starts on the target machine" instead.
- Deferring scope is fine; calling the track complete is not. If a
capability is intentionally out of this pass (FFU), it must NOT
appear as a satisfiable acceptance criterion, and the plan must
carry an explicit unchecked phase for it. A track with deferred
Solution-level capability cannot later be marked
doneat 100%. - Update
test.mdwith test cases for any new phases or requirements. - Check for
## ❌ KPI MISSin plan.md: if present, this is a replanning cycle after a KPI failure. Read the failure data (target, actual, delta, snapshot) and use it as context. Generate a different hypothesis — new content angle, different channel, different CTA. Print:♻️ Replanning with KPI data: target=X, actual=Y, delta=Z. Append a new## ❌ KPI MISSentry (don't overwrite old ones).
- Read existing
- KPI enforcement (for
marketingandsalestracks):- Read
**Type**from index.md. - If type is
marketingorsales: check spec.md for## KPIblock. - If missing: print
⚠️ KPI block required for marketing/sales tracksand write a stub## KPIsection with TODOs. - Block transition to
on_successuntil all required fields are filled: Target, Metric, Source, Threshold. - Required
## KPIblock format in spec.md:## KPI **Target**: <number> **Metric**: <label> **Source**: hn-api | reddit-api | manual | custom-url **Source Config**: <item_id=NNN or URL> **Threshold**: <number> **Window**: <e.g. 48h or 7d> **Maps To**: <metric name from conductor/kpis.md> ← optional
- Read
- Draft section (for non-dev tracks):
- After planning is complete for non-dev tracks: write a
## Draftsection to spec.md (alongside KPI and Requirements). - Draft = publish-ready content the human will execute (post text, email copy, social content).
- Include a
### Publish Instructionssubsection with step-by-step numbered instructions. - Do NOT create a separate
draft.md— everything stays in spec.md. - Moving the track to implement (drag or Run) IS the approval — no extra gate needed.
5b. Fundamentals-conflict guardrail: if, while planning, the track's requirements appear
to conflict with or require a change to one of the project's fundamental docs
(
product-guidelines.md,design-language.md,tech-stack.md,workflow.md) — e.g. the requested UI contradicts the documented design tokens, or a dependency choice conflicts with the documented stack — do NOT silently edit that fundamental doc as part of this track's plan. Instead: - Append a comment to
conductor/tracks/NNN-*/conversation.md:> **system**: ⚠️ FUNDAMENTALS CONFLICT — this track's [requirement] appears to require changing conductor/[doc].md ([specific conflict]). Continuing implementation as specified; doc not modified — please review whether conductor/[doc].md should be updated. - Note the same flag in
spec.md's Requirements section as an open item for human review. - This is non-blocking by default — the track continues through planning; a human reviews and decides whether to update the fundamental doc or adjust the track's approach.
- After planning is complete for non-dev tracks: write a
- Pulse: Update DB status via
/laneconductor pulse NNN planning 0%. - Transition: First re-read
index.md's current**Lane**marker. If it is no longerplan(a human moved the card to a different lane on the board while this run was in progress — e.g. dragged straight toimplementordone), do not overwrite it: leave**Lane**and**Lane Status**exactly as they are, skip the rest of this step, and append> **system**: ℹ️ Plan finished, but the track had already been moved to <current lane> — leaving it there.toconversation.mdinstead of the comment below. The human's manual move always wins over this run's own stale intent. Otherwise (stillplan, the normal case): readconductor/workflow.jsonand set**Lane**inindex.mdto exactly what is defined inlanes.plan.on_success. Then append a completion comment toconversation.md(see Completion Comment Convention below): if step 5b's fundamentals-conflict guardrail fired during this run, use> **system**: ⚠️ Plan complete with a fundamentals conflict — see conversation above.(don't double-post; the guardrail's existing comment plus this one line is enough context); otherwise use> **system**: ✅ Plan complete — moved to <lane>.
🛑 BOUNDARY ENFORCEMENT: Your job ends here. Do NOT start implementing code. Wait for the next worker cycle to pick up the track in its new lane.
/laneconductor brainstorm [track-number]
Optional deepening step. Call this before /laneconductor implement when you want to explore requirements further via dialogue. Not a lane — can be run at any time.
Flow:
- Load all context (if
FRESH_SESSION: false— see Protocol: Session Continuity — skip everything exceptconversation.md; brainstorm is a repeated back-and-forth, so every question-answer round after the first is almost always a resumed session, but you still need the latest human reply): readconductor/product.md,conductor/tech-stack.md,conductor/deployment-stack.md(if present),conductor/tracks/NNN-*/spec.md,plan.md,test.md, andconversation.md - Ask one clarifying question — appended to
conductor/tracks/NNN-*/conversation.mdin this format:> **system**: Brainstorm requested. [Your question here] - Set
**Waiting for reply**: yesinindex.md - Wait for human reply in
conversation.md(or via UI inbox) - Repeat: ask next question based on reply. One question per message.
- When enough context is gathered (or human says "go ahead"), run
/laneconductor plan NNN— it will readconversation.mdand updatespec.md/plan.md/test.mdfrom the dialogue.
What counts as "enough context": requirements are unambiguous, acceptance criteria are clear, at least one test case per phase is implied.
Also available as: lc brainstorm <track-number> (writes initial trigger to conversation.md, sets **Waiting for reply**: yes)
/laneconductor implement [track-number]
Execute implementation tasks. The Skill Worker communicates purely through files.
Updated flow (uses lock/unlock):
- Claim the track immediately — before acquiring the lock, write
**Lane**: implementand**Lane Status**: runningtoconductor/tracks/NNN-*/index.md. Setting**Lane**explicitly matters whenever this command is invoked directly on a track still sitting in an earlier lane (e.g. a human runs/laneconductor implement NNNright after planning, without an intervening move-to-implement step — this project'sworkflow.jsonkeepsplan.on_success: plan:success, so a track does NOT land in theimplementlane automatically) — without it, the Kanban board shows the track "running" in the wrong column for the whole duration of the work. This prevents the worker from double-launching and shows activity in the UI. - Locate the Track: Use the Protocol: Locating Tracks (check
tracks-metadata.jsonfirst) to find the track folderconductor/tracks/NNN-*/. - Acquire lock and worktree:
lock_result = /laneconductor lock {track_number}
worktree_path = lock_result.worktree_path
cd {worktree_path}
- Read existing context (skip entirely if
FRESH_SESSION: false— see Protocol: Session Continuity — exceptconversation.mdandlast_run.log, which you should always check for anything new since your last turn):- Read
conductor/tracks/NNN-*/plan.mdto understand phases - Read
conductor/tracks/NNN-*/spec.mdfor technical details and**Type** - Read
conductor/deployment-stack.md(if present) for deployment context - Read
conductor/product-guidelines.md(if present) for brand/style/UX principles - Read
conductor/design-language.md(if present) for concrete design tokens/conventions - Read
conductor/tech-stack.md(if present) for the project's languages/frameworks/deps - TDD / test.md Self-Healing: Check if
conductor/tracks/NNN-*/test.mdexists and contains real test cases. If it is missing, empty, or contains the generic(Test cases to be added)stub, you MUST generate and write a structuredtest.mdwith concrete test cases and commands for each phase inplan.mdbefore writing any implementation code. - Read
conductor/tracks/NNN-*/test.md— it drives the implementation order. TDD Protocol: for each phase, find its test cases intest.md, write the test code first, run the test and confirm it fails, then write minimal code to make it pass, then confirm green. - CRITICAL: Read
conductor/tracks/NNN-*/conversation.mdif it exists. Treat human comments as overriding instructions. (Always — even when resumed.) - IMPORTANT: Read
conductor/tracks/NNN-*/last_run.logif it exists. This contains why the previous run failed. (Always — even when resumed.) - Update
index.mdto**Status**: implement
- Read
2b. Skill check for non-dev tracks (type = marketing or sales):
- Check
.claude/skills/for recommended skills:- Marketing:
social-content,copywriting,content-strategy,launch-strategy - Sales:
sales-enablement,cold-email
- Marketing:
- Print
⚠️ Track type 'marketing' works best with [skill] — not found in .claude/skills/for missing. - Print
💡 Invoke /[skill] before writing contentfor present skills.
- Non-dev track supervised implement:
- If
**Type**is notdev: this is a supervised implement — do NOT write code. - Read
## Draftfrom spec.md (written by the plan phase). - Output the full publish-ready content to the user with clear formatting.
- Output the
### Publish Instructionsstep-by-step. - Set
**Waiting for reply**: yesin index.md. - The worker will detect "done" reply in conversation.md and automatically schedule the quality gate.
- Stop here — do not transition the lane yourself. The worker handles the transition.
- If
3b. Fundamentals-conflict guardrail (dev tracks): checked against the
product-guidelines.md/design-language.md/tech-stack.md content loaded in step 2 — if
what this track needs to build conflicts with, or implies a needed change to, one of those
fundamental docs (or workflow.md), do NOT silently write code that contradicts them, and
do NOT silently rewrite the fundamental doc either. Append the same ⚠️ FUNDAMENTALS CONFLICT
comment format used in /laneconductor plan to conversation.md, naming the specific doc
and conflict. Non-blocking by default — continue implementing as specified unless the
conflict is severe enough that proceeding would be actively wrong (in which case treat it
like any other blocker: stop and flag for human input instead of guessing).
-
Dev track: For each phase (skip for non-dev tracks):
- Implement tasks
- Before marking any task
[x]or writing a "✅ Phase N complete" summary: actually run whatever verifies it, and look at the real output — a written-but-unexecuted test file, or a plausible-looking diff you reasoned about but never ran, is not verification. This applies even whentest.mdhas no predefined cases for this phase (the TDD Protocol above is not the only trigger for this rule) — if there's a real mechanism to exercise (a CLI flag, an API endpoint, a UI flow, a dispatch), run it for real and confirm the actual behavior, not just that the code compiles/parses. Found and documented the hard way on track 1087's Phase 6: an autonomousimplementrun marked a phase "✅ complete" with a plausible diff and two new test files, but the feature was non-functional (a hardcodednullbroke the one code path meant to matter) and neither test file had actually been executed — one had a hard import error that any single run would have caught immediately. - Never end a turn having just backgrounded a long-running command and nothing else.
The harness kills background children when the session process exits, so a turn that
ends there produces a run that exited 0 mid-work with real work left undone — found and
fixed as track 1102's F21 (original variant): the exit handler now recognizes this as a
distinguishable
ended_mid_workoutcome instead of silently advancing the lane, but that only makes the aftermath visible; it does not prevent it. If a command needs to run longer than this turn should take, either wait for it to finish before ending the turn, or explicitly hand off with a comment inconversation.mdnaming exactly what is still running and what the next turn should check for. - Update
plan.md(⏳ → ✅ per task as completed) - Update
index.md**Progress**marker - Commit:
feat(track-NNN): Phase X - description - Never end your final turn on a just-launched background command (a
backgrounded shell process, an unresumed
&, a detached spawn you intend to check on next turn). The harness kills background children when the session process exits, so the work is silently lost, not paused. If a command must run long, run it in the foreground and wait for it, or explicitly hand off with a note inconversation.mdrather than trusting a background process to survive turn-end. Track 1102 F21 made the aftermath of this mistake visible (an exit-0-mid-runningturn now produces a distinguishable outcome instead of a silentqueue) — that is recovery, not prevention; this rule is the prevention.
-
Dev track: On complete (skip for non-dev tracks):
- Same verification bar as step 4, for the track as a whole, before writing
## ✅ COMPLETE. - Update
index.md**Progress**marker to 100%. - Transition: First re-read
index.md's current**Lane**marker. If it is no longerimplement(a human moved the card elsewhere while this run was in progress), do not overwrite it — leave**Lane**/**Lane Status**as-is and note in the completion comment below that the lane was left untouched because it had already moved. Otherwise: readconductor/workflow.jsonand set**Lane**inindex.mdto exactly what is defined inlanes.implement.on_success. - Append
## ✅ COMPLETEtoplan.md. - Append a completion comment to
conversation.md(see Completion Comment Convention):> **system**: ✅ Implementation complete — moved to <lane>. - Final commit:
feat(track-NNN): Implementation complete
Non-dev (supervised) tracks already set
**Waiting for reply**: yesin step 3 — thatwaiting_for_replymarker is itself the Inbox signal (see Completion Comment Convention andwaiting_for_replyin the marker table above), so no additional completion comment is needed there. - Same verification bar as step 4, for the track as a whole, before writing
-
Release lock and cleanup:
/laneconductor unlock {track_number}
🛑 BOUNDARY ENFORCEMENT: Never override the workflow. Use workflow.json as the sole authority for target lanes.
- If lock fails (already locked): Stop and report error
- If work fails: Still call unlock in finally block to ensure cleanup
- On exit: Update
**Lane Status**: successorqueuebased on exit code
/laneconductor review [track-number]
Structured review of a track against its plan and product guidelines. Posts the result as a comment by writing to the track's conversation file.
- Claim the track immediately — write
**Lane**: reviewand**Lane Status**: runningtoconductor/tracks/NNN-*/index.mdbefore doing anything else (see/laneconductor implement's step 0 for why**Lane**needs setting explicitly, not just**Lane Status**). - Load Context (skip the first bullet if
FRESH_SESSION: false— see Protocol: Session Continuity; review often resumes the same sessionimplementused, so this is worth checking — the second bullet always applies):- Read
plan.md,spec.md,test.md,product-guidelines.md,design-language.md, anddeployment-stack.md(if present). - Read
conversation.mdto see if previous review gaps were addressed or if the user provided specific instructions. (Always — even when resumed.)
- Read
- Evaluate: Check implementation against requirements and guidelines.
- Secrets Policy: Ensure no secrets are hardcoded or leaked in logs. Verify use of ADC/Secret Manager as specified in
deployment-stack.md. - If
test.mdexists, run the test commands listed there. A FAIL verdict is mandatory if any test cases are failing.
- Secrets Policy: Ensure no secrets are hardcoded or leaked in logs. Verify use of ADC/Secret Manager as specified in
- Post Review: Append the review results to
conductor/tracks/NNN-*/conversation.mdas a single> **system**: ...comment (see Completion Comment Convention) — authorsystem, notclaude/gemini, and the emoji is the literal first character of the body, e.g.> **system**: ✅ REVIEW PASSEDor> **system**: ⚠️ REVIEW FAILED, followed by the full write-up (test pass/fail summary iftest.mdwas present, gaps if any) as>-prefixed continuation lines under that same comment — do not post the write-up as a second comment. - Auto-lane transition:
- First re-read
index.md's current**Lane**marker. If it is no longerreview(a human moved the card elsewhere while this run was in progress), do not overwrite it — leave**Lane**/**Lane Status**as-is, still post the review comment from step 3 (the review itself is still valid information), and note there that the lane transition was skipped because the track had already moved. Otherwise, continue below. - Read
conductor/workflow.json. - If PASS: Set
**Lane**to the value oflanes.review.on_successand**Lane Status**toqueue. Append## ✅ REVIEWEDtoplan.md. - If FAIL: Set
**Lane**to the value oflanes.review.on_failureand**Lane Status**toqueue. Add⚠️ Gapstoplan.md.
- First re-read
/laneconductor quality-gate [track-number]
Runs automated checks and updates status files based on results.
-
Claim the track immediately — write
**Lane**: quality-gateand**Lane Status**: runningtoconductor/tracks/NNN-*/index.mdbefore doing anything else (see/laneconductor implement's step 0 for why**Lane**needs setting explicitly, not just**Lane Status**). 0b. KPI window check (early trigger warning):- Read
**KPI Check After**from index.md. If it exists and is in the future:"KPI window not reached — Xh remaining. Measuring now may give unreliable results. Run anyway? (y/n)"
- If user says "n", stop. If "y", proceed.
- If invoked automatically by the worker, the worker already checked the time — skip this warning.
- Read
-
KPI measurement (runs BEFORE code checks):
- Read
**Type**from index.md. - If type is non-dev (
marketing,sales,support,other) OR spec.md has a## KPIblock: runconductor/measure.mjsfor this track. node conductor/measure.mjs --track NNN- Write result back to index.md:
**KPI Actual**: Nand**KPI Snapshot**: {JSON} - If KPI failed (
passed: false):- Append
## ❌ KPI MISStoplan.md:## ❌ KPI MISS — [ISO timestamp] **Target**: T | **Actual**: N | **Delta**: -D | **Window**: W **Snapshot**: `{raw JSON}` - This is a terminal outcome (see Completion Comment Convention) — append to
conversation.md:> **system**: ❌ KPI miss — actual=N, target=T, threshold=TH. - Transition to
on_failurelane. Do NOT run code checks.
- Append
- If KPI passed: append to
conversation.md:> **system**: KPI measurement: actual=N, target=T, threshold=TH, passed=true.— no leading emoji here (this is not yet a terminal outcome; step 4's Post Results is the terminal comment for this run, and gets the emoji) — then continue to code checks below. - Dev tracks without a
## KPIblock: skip measurement entirely.
- Read
-
Execute Checks: Read
conductor/quality-gate.mdand the track'stest.md. You MUST execute EVERY command listed in both files' "Automated Checks" / "Test Commands" sections as shell commands (using your Bash/terminal tool).- The checkboxes in
quality-gate.mdare NOT a report — they are a checklist you must run. That file ships with every box pre-ticked[x]and often a staleStatus: PASSverdict from an earlier run. Those marks say nothing about your track. Re-run every command and judge only by output you personally saw. If you catch yourself reasoning "it's already checked" — stop; that is exactly the failure mode this warning exists for. test.mdtest commands are the primary automated check for this specific track.quality-gate.mdcommands apply project-wide quality standards.- Deployment Safety: Scan modified files for hardcoded secrets (API keys, tokens). Verify that
.gitignorecontains the patterns defined in the Zero-Secrets Policy. - If a command is missing from your system (e.g.,
playwrightnot installed), you MUST install it or report a failure. - Do NOT just mark them as checked; you must actually run the code and verify the output.
- For non-dev tracks that passed KPI: skip code checks (there's no code to check).
2a. Run the product, not just the code. Unit tests only prove code does what its author believed; they cannot tell you a feature is missing. If this track touched UI or any user-facing flow:
- Run the project's browser/E2E suite if
quality-gate.mdnames one (e.g.npx playwright test). A line reading "if UI changes exist, create/run tests" does not license writing one trivial passing test — if specs already exist, run those. - If there's no E2E suite, drive the flow by hand once: start the app, use the thing this track added, confirm the user-visible result, and record what you observed. A screenshot, or the real API/DB response, is evidence. "The code looks correct" is not.
- Restart long-running processes first. Workers and the API server do not hot-reload; verifying against a process started before your change tests the old code and yields a false pass. This has caused several false verdicts in this repo.
2b. Stub / deferred-work scan. Cheap, and catches the most damaging class of false pass:
grep -rniE "not yet implemented|not implemented|TODO|FIXME|FFU|placeholder|stub" \ --include="*.mjs" --include="*.js" --include="*.jsx" --include="*.ts" --include="*.tsx" \ conductor ui bin 2>/dev/null | grep -v node_modules- A hit inside a code path this track's
plan.mdmarks[x]is a FAIL, not a note. A task is not done if the thing it claims to do prints "not yet implemented". - Also grep
index.md/plan.md/spec.mdforFFU, "deferred", "future", "stub". If any capability named inspec.md's Solution is deferred, the track cannot reachdone— see step 5.
2c. Judge against the user-facing promise, not the implementation. Read
spec.md's Problem Statement and Solution and ask: if a user did the thing this track promises, would it work? Acceptance criteria that assert a placeholder ("logs the expected 'not yet implemented' message", "no real code path is exercised") are not met criteria — they describe scaffolding. Record them as a spec defect inconversation.mdinstead of passing the track on them. - The checkboxes in
-
Self-Healing: If a check fails but you can fix it (e.g., a syntax error or missing command), you MAY do so. However, before writing any fix:
- Write a failing test that reproduces the bug first. The test must fail before you fix anything.
- Then implement the fix.
- Re-run to confirm the test now passes.
- You MUST commit both the test and the fix together with
fix(quality-gate): [description]. - You MUST post a comment to
conversation.mdexplaining what failed and what was fixed.
-
Post Results: Append results to
conversation.mdas a single> **system**: ...comment (see Completion Comment Convention) — authorsystem, and the emoji is the literal first character of the body:> **system**: ✅ QUALITY GATE PASSEDon pass, or> **system**: ❌ QUALITY GATE FAILED(or⚠️if it needs human judgment rather than a straightforward retry) on fail, followed by the full results write-up as>-prefixed continuation lines under that same comment — do not post the write-up as a second comment. -
Transition:
- First re-read
index.md's current**Lane**marker. If it is no longerquality-gate(a human moved the card elsewhere while this run was in progress), do not overwrite it — leave**Lane**/**Lane Status**as-is, still keep the results comment posted in step 4 (it's still valid information), and note there that the lane transition was skipped because the track had already moved. Otherwise, continue below. - Read
conductor/workflow.json. - Done-gate — a track may only reach
done(queued for merge) at 100% if the feature actually works end to end. Reachingdone:queuehere is not itself "shipped" — the merge action (/laneconductor merge, track 10035) is what later setsdone:successonce the code actually lands onmain. Before setting thedonelane, confirm all of:- Step 2b's stub scan found nothing in
[x]code paths. - No capability named in
spec.md's Solution is marked FFU / deferred / future. - Step 2a's real-product check was actually performed, with a
recorded observation.
If any fails, you MUST NOT mark the track
done. Set the lane toreview(oron_failure), keep**Progress**below 100%, and write what remains inconversation.md. Honestly documenting a deferral does not make a track complete — a track that shipped a stub and was markeddone: 100%with an honest "SSH deferred (FFU)" note is the exact incident these rules were written for.
- Step 2b's stub scan found nothing in
- If PASS: Set
**Lane**to the value oflanes.quality-gate.on_successand append## ✅ QUALITY PASSEDtoplan.md. - If FAIL: Set
**Lane**to the value oflanes.quality-gate.on_failureand explain the failure inconversation.md. - Update
**Lane Status**toqueue.
- First re-read
/laneconductor merge [track-number]
The done lane's standard lane action (track 10035). Claimed and run exactly like
plan/implement/review/quality-gate — Auto Run gate, parallel_limit, retries, and per-lane model
all apply unchanged. The one structural difference: this action runs in the primary
checkout, on main — never in the track's own worktree (workspace: main, track 1115's
machinery). done:success means the code is actually reachable from local main (direct mode)
or the PR has actually been merged on GitHub (pr mode) — never anything less.
- Claim the track immediately — write
**Lane**: doneand**Lane Status**: runningtoconductor/tracks/NNN-*/index.mdbefore doing anything else (see/laneconductor implement's step 0 for why**Lane**needs setting explicitly). - Run in the primary checkout, not a worktree. Do not call
/laneconductor lockto create a track worktree for this action — take the project's global main-mode lock instead (the same lock otherworkspace: mainlane actions use) and operate directly in the repo root the worker is already running from. Every commit made during this run still references the track (feat(track-NNN): .../Merge track-NNN/ etc.) per the Commit Strategy. - Load context (skip if
FRESH_SESSION: falseand you already read these earlier this session — see Protocol: Session Continuity — exceptconversation.md, always re-read): readconductor/tracks/NNN-*/index.mdfor**Merge Mode**(defaultprif absent) andconductor/tracks/NNN-*/conversation.mdfor any human instructions (e.g. a reconciler comment about a conflicted PR — see step 6 below). - Single-writer rule (REQ-8): from this point on, only the primary checkout's copy of
conductor/tracks/NNN-*/*.mdis ever written. Never write to the branch's/worktree's copy — there should be no worktree checked out for this action in the first place, but if one still exists for this track (leftover fromimplement/review), do not touch its files. - Direct mode (
**Merge Mode**: direct): a. Runlc worktrees merge NNN(bin/lc.mjs'sworktrees mergesubcommand, backed by the sharedmergeWorktreeBranch()primitive inconductor/services/worktree-merge.mjs). This does the whole clean-merge path atomically: scratch-worktree merge, auto-resolves bookkeeping-only conflicts via the existingisSafeToAutoResolveBookkeepingConflictcheck, compare-and-swapmainref update, resync of the primary checkout's working tree, removal of the track's own worktree, and local branch deletion. Prints✅ Merged track-NNN into main (<sha>)and exits 0 on success — go straight to step 4e. If it instead reportstrack-NNN branch not found: this is expected, not a failure, for a track whose**Workspace**: mainmarker meant every prior lane action (implement, review, quality-gate) already ran directly onmain— there was never a branch to merge in the first place, the code is already there. Treat this the same as a successful merge and go straight to step 4e. b. If it exits non-zero with a conflict (stderr lists the conflicting paths, branch and worktree deliberately left intact): this is a real conflict the shared primitive refused to guess at. Resolve it in-session instead —git fetch origin, thengit merge --no-ff track-NNNdirectly in the primary checkout (this run already holds the global main-mode lock, so this is safe), read the conflicting hunks, understand both sides' intent (this track's plan.md/spec.md vs. the conflicting main-side change), and produce a correct merged result. This replaces the old separateai-resolve-conflictaction — there is no other path for a real conflict. c. If step 4b's manual merge succeeds:git push origin main, then delete the track's worktree and branch by hand (git worktree remove --force .worktrees/NNN,git branch -d track-NNN,git push origin --delete track-NNN) — same cleanuplc worktrees mergewould have done. d. If a conflict cannot be safely resolved even in-session (semantic ambiguity, not just textual overlap): do not guess or force it. Set**Lane Status**to the value oflanes.done.on_failure(done:failure) and write exactly what's conflicting toconversation.md— never fall silently back toqueue(AC-6). e. On any successful merge (4a or 4c): set**Lane Status**: success(→done:success). - PR mode (
**Merge Mode**: pr, or marker absent): a. Runlc worktrees create-pr NNN(backed bycreateTrackPr()inconductor/services/pr-flow.mjs, the same primitivemerge-pr/create-prused to use). It pushes the branch, checksgh auth statusfirst (never silently falls back to a local merge ifghisn't authenticated), runsgh pr createif no open PR exists yet for this branch (idempotent — if one already exists, it reports that PR instead of erroring), and writes**PR Number**/**PR URL**/**PR Status**markers into the primary checkout's ownindex.mdonly (REQ-8 — this command always runs from the repo root, so there is no worktree copy for it to accidentally touch). b. If step 5a is a re-run after a conflict (see step 6): the branch was already updated frommainand (force-)pushed in step 6's conflict-resolution flow before reaching here — the existing PR reflects the new push automatically;lc worktrees create-prdetects the already-open PR and is a no-op beyond reporting it. c. Set**Lane Status**: waiting(→done:waiting). Within the done lane,waitingmeans exactly "waiting on a human outside the system" — there is nothing further for this session to do. Do not merge the PR yourself; approval/merge happens on GitHub, and the reconciler (not this command) observes that and closes the loop. - Re-entry after a conflicted PR: if this run was triggered by the reconciler moving the
track back to
done:queueafter detecting a PR conflict (see the reconciler's conflicted-PR handling below), treat it exactly like a normal pr-mode run (step 5) — but first,git fetch originandgit merge origin/main(or rebase) intotrack-NNNdirectly, resolve any real conflict in-session (same rules as step 4b), and push (force-push if the branch was rebased) before runninglc worktrees create-pr NNN— pushing first is what makes step 5a's already-open-PR detection pick up the new commits automatically. This is what closes REQ-7's loop — there is no separate "resolve PR conflict" code path. - Post a completion comment (see Completion Comment Convention): on direct-mode success,
> **system**: ✅ Merged track-NNN to main.; on pr-mode push,> **system**: ⚠️ PR opened — waiting for review: <url>.(⚠️ because it needs human action, not because anything failed); on an unresolved conflict,> **system**: ❌ Merge conflict could not be resolved automatically — see details above.
🛑 BOUNDARY ENFORCEMENT: This command only merges/opens PRs for code that already passed
review and quality-gate. Never write new feature code here — the only code changes permitted are
those strictly required to resolve a merge conflict between the track branch and main.
/laneconductor remote-sync [track-number?]
Bidirectional sync between the local filesystem and the configured Collector API. Uses a "newer wins" strategy based on modification timestamps.
- If the database version is newer: updates the local
index.md. - If the local file is newer: patches the API with the local changes.
- If no track number provided: syncs all tracks in the current project.
/laneconductor comment [track-number] [body]
Post a comment on a track by writing to its conversation file.
- Append
> **system**: [body]toconductor/tracks/NNN-*/conversation.md. - The Sync Worker will sync this comment to the database.
/laneconductor delete [track-number]
Permanently delete a track — removes it from the filesystem, database, and any git locks.
- Find
conductor/tracks/NNN-*/— print the track title so the user can confirm. - Delete the folder:
rm -rf conductor/tracks/NNN-*/ - Remove from
conductor/tracks/file_sync_queue.mdif present (mark entry as**Status**: deletedor remove the entry block entirely). - If
modeislocal-apiorremote-api: callDELETE /api/projects/:id/tracks/NNNto remove from DB. - Remove any stale git lock:
conductor/.locks/NNN.lock - Print:
✅ Track NNN deleted
Warning: This is a hard delete — no undo. For soft-delete/archiving, move to backlog instead.
/laneconductor revert [track] [phase] [task?]
Safe undo at track/phase/task level with DB sync.
Same logic as the conductor revert command, plus:
- After revert: re-parse
plan.md→ recalculateprogress_percent→ pulse DB - If reverting a done track back to a phase: pulse
in-progress
/laneconductor syncdb [--source <url>] [--target <url>]
Migrate track comments between collectors — critical when switching from local-only to cloud, or between workspaces.
Problem: Track metadata (status, progress) re-syncs naturally from filesystem. But comments are DB-only, so switching collectors loses conversation history.
Solution: Export comments from source, apply schema to target, then import.
Usage:
# Export from local DB, import to cloud
node conductor/syncdb.mjs \
--source "postgresql://localhost:5432/laneconductor?..." \
--target "postgresql://cloud-db.supabase.co/postgres?..."
# Save export for manual inspection
node conductor/syncdb.mjs \
--source "postgresql://localhost/laneconductor" \
--export comments.json
# Import previously exported file
node conductor/syncdb.mjs \
--target "postgresql://cloud-db.supabase.co/postgres" \
--import comments.json
What it does:
- Query source:
track_commentsjoin with tracks/projects - Map to target: find matching project + track_number, insert comment
- Touch filesystem: updates plan.md mod times → worker re-syncs tracks
- Instructions: user updates
.laneconductor.jsoncollectors config + runslc stop,lc start
Important:
- Only comments are synced — tracks re-sync from disk automatically
- Schema must exist on target (created if missing)
- Duplicate detection: tries to find matching project/track by name; skips if not found
- User must manually update config + restart worker
/laneconductor remote-sync [track-num?]
Phase 5 Implementation — Sync track changes from the Collector API back to local filesystem.
Problem: When using a remote Collector API/database, UI changes (dragging tracks to lanes, updating progress) happen in the DB but don't reach the local worker's filesystem. The worker can't see them.
Solution: A bidirectional sync mechanism where the Skill reads from the API and writes to local files.
Usage:
# Sync a single track from DB to file
/laneconductor remote-sync NNN
# Sync all tracks from DB to files
/laneconductor remote-sync
What it does:
- Read
.laneconductor.jsonfor collector URL and project ID - Fetch tracks from
GET /api/projects/:id/tracksendpoint - For each track returned:
- Extract:
track_number,title,lane_status,lane_action_status,progress_percent,current_phase - Find or create
conductor/tracks/NNN-*/index.md - Update markers:
**Lane**,**Lane Status**,**Progress**,**Phase** - Use regex to update existing markers or prepend new ones
- Extract:
- Update
.conductor/tracks-metadata.jsonwith sync timestamps - Log results: number of tracks updated, any conflicts or errors
- Automatically triggers Phase 6 to regenerate
conductor/tracks.md
Architecture:
- Skill reads API (not DB directly) — ensures it works with both local and remote collectors
- Writes local files — respects filesystem-as-source-of-truth for worker
- Timestamp-based conflict resolution — newer timestamp (file vs DB) wins
- Metadata tracking —
conductor/.tracks-metadata.jsonstoreslast_db_updateper track for conflict resolution
Only activates if:
.laneconductor.jsonhas acollectorsarray with at least one configured collector- Track files exist locally (creates them if missing, but won't create new track folders)
/laneconductor init-tracks-summary
Phase 6 Implementation — Regenerate conductor/tracks.md from all track files.
Problem: conductor/tracks.md is an aggregate summary that needs to be kept in sync with all individual track files.
Usage:
# Regenerate full summary from all track files
/laneconductor init-tracks-summary
What it does:
- Scan
conductor/tracks/directory for all folders containing a number (matches both legacyNNN-slugand prefixedINITIALS-NNN-slugformats) - For each track folder, read
index.mdand extract:- Track number and slug from folder name (extract number via
/\d+/match regardless of prefix) - Title from
**Title**marker (fallback to slug) - Lane from
**Lane**marker (default: 'planning') - Progress from
**Progress**marker (default: 0%)
- Track number and slug from folder name (extract number via
- Generate
conductor/tracks.mdwith:- Header: Last Updated timestamp (ISO format)
- Summary line: Total tracks, counts per lane
- Grouped sections by lane: planning, in-progress, review, quality-gate, backlog, done
- Each track listed as:
- **NNN**: Title (XX%)
- Tracks sorted numerically within each lane
Example output:
# Track Summary
Last Updated: 2026-02-27 13:11:20 UTC
Total Tracks: 34 | Planning: 4 | In-Progress: 2 | Review: 2 | Quality-Gate: 2 | Done: 20
## Planning
- **1011**: Update Product
- **1012**: Git Worktree Per Track (0%)
## In progress
- **NNN**: Sync Manager (45%)
...
Trigger Points:
- Automatically runs after
/laneconductor remote-sync - Can be run manually at any time
- Worker could trigger this after
/laneconductor pulseupdates a track
Benefits:
- Always reflects current state of all tracks (no stale summary)
- Grouped by lane for quick status overview
- Percentage progress shows at a glance what's done
- Baseline data for dashboard Kanban board
Track File Templates
plan.md
# Track NNN: [Title]
## Phase 1: [Phase Name]
**Problem**: What issue does this solve?
**Solution**: How will it be solved?
- [ ] Task 1: Description
- [ ] Sub-task: Details
- [ ] Task 2: Description
**Impact**: What will change?
spec.md
# Spec: [Feature Name]
## Problem Statement
[What problem does this solve?]
## Requirements
- REQ-1: ...
## Acceptance Criteria
- [ ] Criterion 1
## API Contracts / Data Models
[If applicable]
index.md
# Track NNN: [Title]
**Status**: backlog
**Progress**: 0%
## Problem
[One sentence]
## Solution
[One sentence]
## Phases
- [ ] Phase 1: [name]
test.md
# Tests: Track NNN — [Title]
## Test Commands
```bash
# Run all tests
npm test
# Run specific test file
npm test -- path/to/test.spec.js
Test Cases
Feature: [Feature Name]
- TC-1: [Description] — expected: [outcome]
- TC-2: [Description] — expected: [outcome]
Acceptance Criteria
- All unit tests pass
- No regressions in related features
---
## DB Schema Reference
```sql
CREATE TABLE IF NOT EXISTS projects (
id SERIAL PRIMARY KEY,
name TEXT NOT NULL,
repo_path TEXT UNIQUE NOT NULL,
git_remote TEXT,
git_global_id UUID UNIQUE, -- UUID v5 from git_remote (URL namespace); null if no remote
primary_cli TEXT DEFAULT 'claude', -- claude|agy|gemini|other
primary_model TEXT,
secondary_cli TEXT, -- optional second agent
secondary_model TEXT,
created_at TIMESTAMP DEFAULT NOW()
);
CREATE TABLE IF NOT EXISTS tracks (
id SERIAL PRIMARY KEY,
project_id INTEGER REFERENCES projects(id) ON DELETE CASCADE,
track_number TEXT NOT NULL,
title TEXT NOT NULL,
lane_status TEXT DEFAULT 'backlog', -- backlog|in-progress|review|quality-gate|done
progress_percent INTEGER DEFAULT 0,
current_phase TEXT,
content_summary TEXT,
sync_status TEXT DEFAULT 'synced',
last_updated_by TEXT DEFAULT 'human',
last_heartbeat TIMESTAMP DEFAULT NOW(),
created_at TIMESTAMP DEFAULT NOW(),
created_by_email TEXT, -- author email (NULL for legacy tracks)
author TEXT, -- author initials (e.g. AM); NULL for legacy tracks
UNIQUE(project_id, created_by_email, track_number) -- NULL emails are each distinct in Postgres
);
Status Badges → Lane Mapping
| Badge in plan.md | lane_status in DB |
|---|---|
| ⏳ IN PROGRESS | in-progress |
| ✅ QUALITY PASSED | done |
| ✅ REVIEWED | on_success lane from workflow.json (default: quality-gate) |
| ✅ COMPLETE (no open tasks) | review |
| 🔄 BLOCKED | review |
| ⚠️ PARTIAL | review |
| (none / new) | planning |
| (none in DB, explicitly backlog) | backlog |
Note: ✅ COMPLETE with all checkboxes ticked moves to review (ready for review). Only ✅ REVIEWED (added automatically by the review skill on PASS) moves to done. New tracks created via /laneconductor newTrack or the UI land in planning (staging area) — drag to in-progress to start auto-implement, or drag to backlog to defer.
Multi-Project Notes
- Each project has its own
.laneconductor.jsonwith its uniqueproject.id - All projects share one Postgres DB (
laneconductor) - The Vite UI shows all projects; heartbeat workers are per-project
- Project identity key =
repo_path(absolute path) - Run
setup collectionin each repo once; runlc startper active session
Commit Convention
feat(track-NNN): brief description
fix(track-NNN): bug fix
docs(track-NNN): documentation
refactor: changes across multiple tracks
Handling Automation Failures
If a track fails during automation (e.g. auto-implement), it will increment its retry count.
- Max Retries: Default is 1 (configured in
workflow.md). - Blocking: Once reached,
lane_action_statusbecomesblocked.
To Unblock/Reset: Perform ANY human intervention:
- Comment: Add a message to the track thread (
/laneconductor pulse). - Move: Drag the track to a different lane in the UI.
- Implement: Click "Re-run Implement" in the UI.
The system adds a "Moved to [lane]" or "Human comment" marker which resets the retry count to 0 for the worker.
Dev Logging (Worker + API)
Track 1075: the heartbeat worker (conductor/laneconductor.sync.mjs) and the Collector API
(ui/server/index.mjs) each have a structured Pino logger (conductor/services/logger.mjs and
ui/server/logger.mjs respectively) that fans out to two destinations:
- stdout — unchanged from before; still captured into
conductor/.sync.log/ui/.api.logbybin/lc.mjs's spawn redirect, so existingtail -fworkflows keep working. - A standalone Pinorama log viewer — a live, searchable web UI showing both processes' logs
together, filterable by
component("worker"or"api").
Why a standalone instance, not the documented node app.js | pinorama pipe: both the worker
and API are detached background daemons managed by PID file (lc worker start/stop, lc api start/stop), not a single foreground process — there's nothing to pipe. Instead, both loggers
ship to a persistently-running pinorama --server instance via pinorama-transport (an HTTP
transport target), started/stopped independently.
Managing the viewer:
lc logs start # starts the standalone Pinorama server (port 6201)
lc logs stop
lc logs status
lc logs open # starts it if needed, then opens http://localhost:6201 in a browser
lc worker start, lc worker restart, and lc api start all best-effort auto-start the log
viewer already — you usually don't need to call lc logs start yourself.
Port/storage convention — do not reuse for anything else: this runs on port 6201 with its
own storage file (<install-path>/.pinorama.msp), deliberately different from the default port
(6200) and storage path a managed project might use for its own Pinorama instance (e.g.
coachai's make local-start pipes its dev server into pinorama --open on the default port).
The two must never collide — always use 6201 (or LC_PINORAMA_PORT) for LaneConductor's own
logs, never the default.
Logging from worker/API code: import the shared logger and call it like any Pino logger —
logger.info({ trackNumber }, 'message'), logger.warn({ err }, 'message'),
logger.error({ err }, 'message'). Only a handful of the noisiest existing console.* call
sites have been migrated so far (proof of concept, not a full migration) — new code should use
logger directly rather than console.*.
Best Practices
- Keep index.md lean: It is the "Status File" for the project. Always update it when status or progress changes.
- Fast Summary: Avoid reading all
plan.md/spec.mdfiles for deep summaries. Use/laneconductor summarize. - Phase Tracking: Keep checkboxes in
plan.mdup to date. The sync worker uses these to calculate % progress automatically.
Quick Reference
| Command | What it does |
|---|---|
/laneconductor setup |
Run AI-powered scaffold |
/laneconductor setup scaffold |
Create context files (product.md, tech-stack.md, deployment-stack.md, etc.) |
/laneconductor setup-deploy |
AI-guided deployment setup (writes deployment-stack.md + deploy.json) |
/laneconductor deploy [env] |
Execute deployment for a specific environment (prod/staging/preview) |
/laneconductor qualityGate [NNN] |
Run automated quality checks |
/laneconductor start |
Start heartbeat worker (or: lc start) |
/laneconductor stop |
Stop heartbeat worker (or: lc stop) |
/laneconductor status |
Kanban board from DB (or: lc status) |
/laneconductor workflow |
Display lane automation config (transitions, retries, models) |
/laneconductor workflow set [lane] [key] [value] |
Edit a workflow setting in conductor/workflow.json |
/laneconductor newTrack [name] [desc] |
Create track + DB row |
/laneconductor updateTrack [NNN] [what] |
Add work/bug/feature to existing track, move back to backlog |
/laneconductor reportaBug [desc] |
Smart bug intake — updates existing track or creates new bug track |
/laneconductor featureRequest [desc] |
Smart feature intake — updates existing track or creates new feature track |
/laneconductor brainstorm [NNN] |
Optional pre-implement dialogue via conversation.md to deepen spec/plan |
/laneconductor implement [NNN] |
Execute track with DB sync |
/laneconductor revert [track] [phase] |
Safe undo + DB sync |
/laneconductor pulse [NNN] [status] [%] [summary] |
Manual DB update |
/laneconductor comment [NNN] [body] |
Post comment as AI agent (⚠️ BLOCKED / ℹ️ NOTE) |
/laneconductor delete [NNN] |
Hard-delete track: remove folder + DB row + git lock |
/laneconductor review [NNN] |
Review track against plan + guidelines → post result, auto-transition lane |
/laneconductor merge [NNN] |
Done-lane merge action: direct merge to main or open a PR, in the primary checkout |
/laneconductor remote-sync [track-num?] |
Sync track changes from API to local files (Phase 5) |
/laneconductor init-tracks-summary |
Regenerate conductor/tracks.md from all track files (Phase 6) |
lc brainstorm <track> |
Start brainstorm dialogue for a track via conversation.md |
lc start |
Start heartbeat worker |
lc stop |
Stop heartbeat worker |
lc status |
Quick track list |
lc ui start |
Start Vite dashboard |
lc ui stop |
Stop Vite dashboard |
Operating Mode Configuration
LaneConductor supports three operating modes, selected by the mode field in .laneconductor.json:
1. local-fs (pure filesystem)
The worker reads and writes Markdown files only. No Collector API or Database is required.
- Set via:
"mode": "local-fs" - Best for: Offline development, CI pipelines, and automated tests.
- Workflow: Progress is tracked via
**Lane**and**Lane Status**markers inindex.md.
2. local-api (local Postgres + Kanban UI)
The worker syncs with a local Collector API backed by a local Postgres database.
- Set via:
"mode": "local-api" - Best for: Daily development with the full Vite Kanban dashboard.
- Workflow: Full bidirectional sync between filesystem and local database.
3. remote-api (cloud / self-hosted)
Identical to local-api but connects to a remote Collector URL.
- Set via:
"mode": "remote-api" - Best for: Team collaboration and multi-machine setups.
Auto-detection Rules
If the mode field is omitted from .laneconductor.json, LaneConductor infers the mode from the collectors array:
- No collectors: defaults to
local-fs. - Collector URL contains
localhostor127.0.0.1: defaults tolocal-api. - Any other URL: defaults to
remote-api.
Version History
-
4609e87
Current 2026-09-03 08:14
修复轨道文件夹解析逻辑,提取纯模块确保worker与skill一致性;新增lc track-dir子命令;修正完成度门控错误,恢复至正确阶段状态。
-
371408e
2026-08-28 10:05
feat(track-1115): 实现了主分支与分支工作区模式解析器、Worker 连接逻辑、CLI/技能支持、UI/数据库集成及相关文档。
-
5f6779a
2026-08-19 23:50
新增lc worker run命令支持单任务前台运行;添加--only-tracks和--once参数实现Worker作用域限制与单次执行;引入claim-scope机制防止误抢任务;完善测试覆盖。
- 4a81bf8 2026-07-25 05:34


