Your agent pushed this as done. Spot the bug.

Real code, real council. Take a look, then press convene.

$ curl -fsSL https://dootsabha.pages.dev/install.sh | sh
no API keysyour CLI loginsJSON + exit codes
internal/cli/progress.go · as first pusheddootsabha #37
1func openProgressLog(path string) (*progressLog, error) {
2 f, err := os.OpenFile(path,
3 os.O_WRONLY|os.O_CREATE|
4 os.O_TRUNC|os.O_APPEND, 0o644)
5 if err != nil {
6 return nil, fmt.Errorf("progress file: %w", err)
7 }
8 return &progressLog{f: f, start: time.Now()}, nil
9}
10
11// Callers hold p.mu.
12func (p *progressLog) write(ev any) {
13 line, err := json.Marshal(ev)
14 if err == nil {
15 _, err = p.f.Write(append(line, '\n'))
16 }
17}
P1Point it at your config: O_TRUNC erases it, and the run still exits 0.L4
P1A FIFO nobody reads blocks this write while the lock is held. Shutdown hangs.L15
P2Two runs on one path interleave and corrupt the stream.L4
P2A short write leaves half a JSON line behind.L15
BLOCK · 4 of 9 findings shownsee the PR ↗
codexgrok

from real sittings

Not just this diff. Six more it stopped.

  1. 01
    security · P1

    The health check passed an open firewall.

    A leftover rule let sandboxes reach host SSH. The check said healthy, and the work had been called done.

    codexa private project
  2. 02
    security · design

    A reinstalled plugin would inherit every grant.

    Permissions were keyed on the plugin's name: same name, same powers. Caught before any code was written.

    claudecodexshux #33 ↗
  3. 03
    data loss · P1

    A truncated recording, still marked lossless.

    Two names for one file, a case alias or a hard link, let a second pane overwrite a live recording.

  4. 04
    process safety · blocker

    The reaper could kill a stranger.

    It signalled a saved process group after the leader was gone; whoever reused the pid took the SIGKILL.

  5. 05
    wrong result · major

    A timed-out chair exited 0.

    The fallback chair hid the timeout, so callers read success. codex caught it; grok did not.

  6. 06
    said done, wasn't · overclaim

    “All four sites are guarded.” Two were.

    grok, reviewing the branch that made it the default, broke the config and watched zero tests fail.

why more than one

Neither model found them all.

codex8 / 9
grok6 / 9
together9 / 9

Self-review rarely fixes reasoning.1

Judges favour their own answers.23

A mixed panel judges better than one model.45

for the human watching

Watch it deliberate.

Each stage, each agent, live in your terminal. Your agent asks for --json and gets none of this.

preṣaṇa dispatchsamīkṣā peer reviewsaṃśleṣaṇa synthesis
a real run · 6 min 43 s, replayed at 60×

for the agent calling it

A contract, not a chat.

--json

Exactly one document on stdout. Logs stay on stderr.

schema_version: 1

On every JSON document. Fields are added, never renamed.

exit 0 2 3 4 5 6

One code per caller action. Branch on it; never parse prose.

--progress-file

NDJSON to tail while it runs. The last line holds the exit code.

status --json

Which agents are installed and answering, before you plan.

--timeout

A budget per call, a ceiling per run. Both exit 4 and say which fired.

SIGTERM

Every agent stops first. The run still records how it ended.

npx skills add

A skill that tells your agent when to convene and how to read the result.

No API keys. Your subscriptions.

$ dootsabha status
PROVIDERVERSIONMODELSTATUS
agy1.5.1Gemini 4 Argon✓ OK
claude2.1.322claude-opus-5-5✓ OK
codex0.167.0gpt-6.1-sol✓ OK
grok1.0.70grok-4.7✓ OK
never exportedANTHROPIC_API_KEYOPENAI_API_KEYGEMINI_API_KEYXAI_API_KEYOPENROUTER_API_KEY

It runs the CLIs you already pay for, signed in as you.

0keys to rotate
0gateways
0new bills

Made for agents, not eyeballs.

$ dootsabha sabha --agents codex,grok \
--json --progress-file run.ndjson \
"$(git diff main)" > verdict.json
dispatch
codex okgrok ok
review
codex okgrok ok
synthesis
codex · chair ok
finished
exit 0BLOCKthe run worked; the diff didn't
case $? in
  0|5) jq .synthesis verdict.json ;;  # 5: one agent down
  4)   retry --timeout 20m ;;
  3)   dootsabha status ;;
  2|6) fix_the_call ;;
esac

your defaults

One file sets the rules.

Each seat's model and effort, the chair, the budgets. A flag overrides any of it for one run.

--chair--rounds--timeoutdootsabha config show
config.yaml~/.config/dootsabha
providers:  codex:    model: gpt-6.1-sol  grok:    model: grok-4.7    flags: [--reasoning-effort, high]  claude:    model: claude-opus-5-5council:  chair: claude        # who writes the verdict  rounds: 1            # up to 5timeout: 10m           # each agent callsession_timeout: 30m   # the whole sitting

Your next PR, on trial.

  • councilsabhā
  • consultparāmarśa
  • reviewsamīkṣā
  • refinesaṃśodhana
$ curl -fsSL https://dootsabha.pages.dev/install.sh | sh$ npx skills add indrasvat/dootsabha$ dootsabha status
  1. 1Huang 2023
  2. 2Panickssery 2024
  3. 3Zheng 2023
  4. 4Verga 2024
  5. 5Du 2023
  6. 6Karpathy · llm-council
Dūtasabhā · a council of messengersmade with and red ink by indrasvatMIT · github.com/indrasvat/dootsabha