Manage a local Cistern installation — an agentic workflow orchestrator that routes work through LLM-powered pipelines. Use when the user wants to: (1) add, view, or manage droplets (units of work), (2) check pipeline status or aqueduct health, (3) start or restart the Castellarius daemon, (4) view or interact with the dashboard, (5) troubleshoot stuck or failed work, (6) understand Cistern's pipeline stages or vocabulary. Triggers on: "add droplet", "cistern status", "ct status", "ct droplet", "castellarius", "aqueduct", "cataractae", "check the pipeline", or any question about Cistern.
Cistern is an agentic workflow orchestrator. It routes units of work called droplets through configurable pipelines called aqueducts, where each stage is a cataractae handled by an LLM-powered agent.
| Term | Meaning |
|---|---|
| Droplet | Atomic unit of work — always say "droplet", never "task/item/ticket" |
| Cistern | The reservoir — droplets queue here before processing |
| Aqueduct | Named pipeline (e.g., virgo, marcia, julia, appia) |
| Cataractae | A stage within an aqueduct (implement → review → qa → delivery) |
| Castellarius | The overseer daemon — routes droplets, manages pipelines |
| Recirculate | Send a droplet back for revision |
| Drought |
| Idle state — maintenance hooks run here |
| Filtration | LLM refinement that sharpens a rough idea into well-specified droplets before they enter the pipeline |
Never say "drop/item/task/ticket/issue" for work units — always droplet.
~/go/bin/ct~/.cistern/cistern.yaml~/.cistern/cistern.db~/.cistern/castellarius.loghttp://192.168.0.138:5737 (ttyd)cd ~/cistern && COMMIT=$(git rev-parse --short HEAD) && PATH="/usr/local/go/bin:$PATH" go build -ldflags "-X main.version=${COMMIT} -X main.commit=${COMMIT}" -o ~/go/bin/ct ./cmd/ct/| Repo | Prefix | Aqueducts |
|---|---|---|
| cistern | ci- | virgo, marcia |
| ScaledTest | st- | julia, appia |
| PortfolioWebsite | pw- | anio |
Never edit ~/cistern directly. That's the primary clone — touching it corrupts all agent worktrees.
All manual Cistern work goes in the primary clone at ~/cistern:
cd ~/cistern
git checkout -B lobsterdog-work origin/main # Always sync before starting
ScaledTest worktree: ~/.cistern/sandboxes/ScaledTest/lobsterdog
⚠️ Do NOT use ~/.cistern/sandboxes/cistern/ for manual work — that entire directory is owned by the Castellarius pipeline. A lobsterdog worktree there was removed 2026-04-02; placing anything inside the sandbox root risks collision with the pipeline.
implement → review → qa → security-review → docs → delivery
| Complexity | Code | Notes |
|---|---|---|
| standard | 1 | minimal scrutiny |
| full | 2 | standard scrutiny |
| critical | 3 | maximum scrutiny (security review included) |
⛔ Always get explicit confirmation before filing any droplet.
ct droplet add \
--title "Short imperative description" \
--repo <repo-name> \
--complexity standard \
--description "What, why, acceptance criteria"
Filtration is a thinking tool, not a filing tool. It refines ideas into clear specs — filing is always done separately with ct droplet add.
⚠️ Filtration pitfalls:
ANTHROPIC_API_KEY before running ct filter — ct filter uses claude CLI OAuth, not API key auth. Setting ANTHROPIC_API_KEY in the environment causes claude to attempt API key auth, which fails with "Invalid API key" and ct filter exits with a confusing usage-help message.ct filter from ~/cistern — it uses --allowedTools to read codebase context. Running from another directory gives the agent no context.--description for long text — pass the title only; provide full context in the first interactive turn instead.Step 1 — Start (from ~/cistern, no ANTHROPIC_API_KEY exported):
cd ~/cistern
ct filter --title "Rough idea"
Step 2 — Resume with answers:
ct filter --resume <session-id> "answers and context..."
Step 3 — When spec is approved, file manually:
# File each droplet explicitly, wiring deps with --depends-on
ct droplet add --title "First droplet" --repo <repo> --complexity standard \
--description "..."
ct droplet add --title "Second droplet" --repo <repo> --complexity standard \
--description "..." --depends-on <first-id>
Rules:
ct droplet add --filter — fires-and-forgets, no conversationct filter --file — the finalize JSON step is lossy and drops depends_on; always file manually after filtration--depends-on <id> rather than injecting notes into flowing workWhen running on Telegram (channel=telegram), use inline buttons at decision points instead of waiting for typed responses. Send buttons with:
CHAT_ID=8569372105
openclaw message send --channel telegram --target "$CHAT_ID" \
--message "<summary of current spec>" \
--buttons '<buttons-json>'
After each filtration round (present the numbered spec, then):
[ [{"text":"✅ Ready to file","callback_data":"filter:file"},
{"text":"🔄 Another round","callback_data":"filter:continue"}],
[{"text":"❌ Cancel","callback_data":"filter:cancel"}] ]
Button click responses arrive as callback_data: filter:file etc. Map them:
filter:file → file each droplet manually with ct droplet add, wiring --depends-on explicitly; confirm each ID after filingfilter:continue → ask what to refine, do another roundfilter:cancel → confirm cancellation, do not file# Status
ct status
ct droplet list
ct droplet list --repo <repo>
ct droplet show <id>
# Manage
ct droplet restart <id> # Restart from current cataractae
ct droplet restart <id> --cataractae delivery # Re-enter at a specific cataractae
ct droplet pool <id>
ct droplet cancel <id> --reason "..."
ct droplet note <id> "..."
ct droplet deps <id> --add <dep-id>
# Daemon
ct castellarius start/status
journalctl --user -u cistern-castellarius -f
systemctl --user restart cistern-castellarius
# Cataractae
ct cataractae list
ct cataractae generate
# Dashboard (reload after rebuild)
kill $(ss -tlnp | grep 5737 | grep -o 'pid=[0-9]*' | cut -d= -f2) 2>/dev/null
systemctl --user start cistern-ttyd.service
cistern-castellarius.service (Restart=always)~/.claude/.credentials.json — no ANTHROPIC_API_KEY env var needed in servicestart-castellarius.sh just runs exec ct castellarius start — no credential setupcistern-ttyd.serviceRun ct doctor first — it checks daemon status, claude CLI auth, and common config issues automatically.
| Symptom | Check |
|---|---|
| Castellarius not running | systemctl --user status cistern-castellarius → start it |
| Castellarius hung/log quiet | ct doctor flags it automatically; manual check: cat ~/.cistern/castellarius.health (shows last tick time + poll interval) |
| Sessions failing auth | ct doctor checks claude CLI authenticated automatically; also verify nothing sets ANTHROPIC_API_KEY in env — if set, claude switches from OAuth to API key mode and fails |
| Droplet stuck | ct droplet show <id> — check notes; ct droplet restart <id> |
| Logs | journalctl --user -u cistern-castellarius -f or cat ~/.cistern/castellarius.log |
| Dashboard stale after rebuild | Kill old process on port 5737, restart cistern-ttyd.service |
| Binary out of date | Rebuild: cd ~/cistern && COMMIT=$(git rev-parse --short HEAD) && PATH="/usr/local/go/bin:$PATH" go build -ldflags "-X main.version=${COMMIT} -X main.commit=${COMMIT}" -o ~/go/bin/ct ./cmd/ct/ |