Choragos - Μια ομάδα από coding agents, χωρίς να χάσεις τον έλεγχο
// Το Choragos τρέχει μια ομάδα από AI coding agents με πραγματικό καταμερισμό εργασίας: έναν orchestrator που σχεδιάζει και αναθέτει, workers με δικό τους context, μοντέλο και credentials, και ένα πρωτόκολλο delegate/work-done που μεταφέρει τη δουλειά ανάμεσά τους. Μια περιήγηση στο v0.11.2, με συνταγές configuration για πραγματικές ομάδες.
Έχεις τρία παράθυρα Claude Code ανοιχτά. Το ένα γράφει το feature, το δεύτερο κάνει review σε ό,τι έγραψε το πρώτο, και το τρίτο υποτίθεται ότι θα τρέξει τα release checks όταν τελειώσουν τα άλλα δύο. Το message bus είσαι εσύ. Αντιγράφεις μια περίληψη του diff από το πρώτο παράθυρο στο δεύτερο, κάνεις paste πίσω τα ευρήματα του review, και κάθε λίγα λεπτά περνάς και από τα τρία για να δεις ποιο κάθεται σε ένα prompt και περιμένει μια απάντηση που δεν ήξερες ότι χρειάζεται.
Αυτό αντέχει κάπου είκοσι λεπτά. Μετά ο reviewer τελειώνει την ώρα που εσύ διαβάζεις το output του coder, τα ευρήματά του χάνονται στο scroll, και ο coder ξεκινάει δεύτερο refactor πάνω σε κώδικα που ο reviewer μόλις είχε επισημάνει. Κανείς δεν έκανε λάθος. Απλώς δεν υπάρχει πρωτόκολλο.
Αυτό που λείπει δεν είναι περισσότερος παραλληλισμός. Είναι καταμερισμός εργασίας και ένα συμβόλαιο. Ένας agent πρέπει να κρατάει το πλάνο και να μοιράζει τη δουλειά. Οι υπόλοιποι πρέπει να παίρνουν ένα task ο καθένας, στο δικό του context, με το δικό του μοντέλο και τα δικά του credentials, και να αναφέρουν πίσω σε μορφή που αυτός που σχεδιάζει μπορεί να αξιοποιήσει. Τρεις agents που τρέχουν δίπλα δίπλα δεν σου δίνουν τίποτα από αυτά: σου δίνουν τρία transcripts και έναν άνθρωπο στη μέση που μετατρέπει το ένα στο άλλο.
Άρα το ερώτημα δεν είναι πώς οδηγείς τρία παράθυρα ταυτόχρονα. Είναι πώς μοιάζει η ομάδα, και τι μεταφέρει τη δουλειά από τη μία θέση στην άλλη.
Σε αυτό το post βλέπουμε το Choragos και το release v0.11.2: το μοντέλο της ομάδας, το πρωτόκολλο delegate/work-done που μετακινεί τη δουλειά ανάμεσα στους ρόλους, τις συνταγές configuration που χρησιμοποιώ στην πράξη, και τα σημεία όπου υστερεί.
Ποιον αφορά αυτό το post;#
Το post απευθύνεται σε:
- Engineers που τρέχουν πάνω από έναν coding agent ταυτόχρονα και έχουν κουραστεί να είναι το copy-paste layer ανάμεσά τους
- SREs και platform engineers που θέλουν η δουλειά των agents να είναι observable: τι έτρεξε, πόση ώρα πήρε, πόσο κόστισε και τι μπορεί να γίνει rollback
- Ομάδες σε regulated περιβάλλοντα που χρειάζονται κάθε prompt ενός agent να περνάει από ένα gateway που ελέγχουν οι ίδιες, πριν φτάσει σε model provider
- Όποιον έχει προσπαθήσει να στήσει μόνος του τον συντονισμό των agents με scripts και θέλει να δει πώς πρέπει να μοιάζει το συμβόλαιο ανάμεσα στους ρόλους
Τι είναι το Choragos;#
Το Choragos είναι ένα μοναδικό Go binary που τρέχει μια ομάδα από AI coding agents. Ορίζεις την ομάδα σε ένα config file, μία θέση ανά ρόλο: έναν orchestrator που σχεδιάζει και αναθέτει και δεν υλοποιεί ποτέ, και workers που ο καθένας παίρνει ένα brief, ένα μοντέλο και ένα scope. Η δουλειά μετακινείται ανάμεσά τους με ένα πρωτόκολλο που το καλούν οι ίδιοι οι agents, και το deck παρακολουθεί κάθε task σε ένα board.
Το όνομα βγαίνει από τον χορηγό (choragos), τον πολίτη που στην κλασική Αθήνα ηγούνταν του χορού και τον χρηματοδοτούσε. Εδώ ηγείται ενός χορού από agents.
Τέσσερα πράγματα που σου δίνει και που τρία παράλληλα παράθυρα δεν σου δίνουν:
- Καταμερισμό εργασίας που τον δηλώνεις εσύ. Ο orchestrator κρατάει το πλάνο. Κάθε worker είναι ξεχωριστό process με δικό του context, δικό του μοντέλο και δικό του environment, οπότε ο reviewer είναι πραγματικά μια δεύτερη γνώμη και όχι το ίδιο μοντέλο που βαθμολογεί το δικό του γραπτό.
- Ένα συμβόλαιο ανάμεσα στις θέσεις. Τα
choragos delegate --to coder --task "..."καιchoragos work-doneείναι CLI commands που τα καλούν οι agents. Κάθε delegation παίρνει ένα task ID και καταλήγει σε ένα board, οπότε ένα task που δεν ολοκληρώθηκε φαίνεται, αντί να χαθεί σιωπηλά. - Έλεγχο στις δύο στιγμές που μετράνε. Το
approve = trueβάζει gate σε ένα delegation πριν γίνει η δουλειά, και κάθε delegation παίρνει πρώτα snapshot του workspace, οπότε τοchoragos rollback T3αναιρεί ακριβώς εκείνο το task όταν διαπιστώσεις ότι πήγε στραβά. - Προαιρετικά, ένα compliance gateway στο data path. Με το Sphragis ενεργό, το LLM traffic κάθε agent δρομολογείται μέσα από ένα τοπικό gateway που κάνει redact τα PII και γράφει ένα tamper-evident audit log, και όσο το gateway είναι κάτω το delegation απορρίπτεται.
Το gateway είναι προαιρετικό. Το Choragos τρέχει και standalone, και κάθε feature υποβαθμίζεται ομαλά χωρίς αυτό.
Γιατί όχι subagents ή ένα script γύρω από το tmux;#
| Κριτήριο | Το στήνεις μόνος σου με scripts | Subagents μέσα στον agent | Choragos |
|---|---|---|---|
| Ποιος σχεδιάζει τη δουλειά | Εσύ | Ο parent agent | Μια θέση orchestrator που της δίνεις εσύ το brief |
| Παράδοση της δουλειάς | Γράφεις εσύ το πρωτόκολλο | Ο μηχανισμός του vendor | delegate / work-done πάνω από socket |
| Context ανά worker | Κοινό ή με το χέρι | Κληρονομείται από τον parent | Ξεχωριστό process, ξεχωριστό context |
| Πολλοί vendors | Ναι, αν γράψεις script για τον καθένα | Όχι, ένας vendor | Ναι, οποιοδήποτε binary στο PATH |
| Απομόνωση ανά ρόλο | Ό,τι κάνει export το shell | Το environment του parent | env_allow / env_deny ανά ρόλο |
| Ανθρώπινο gate σε ένα task | Κανένα | Εξαρτάται από τον vendor | approve = true ανά ρόλο |
| Αναίρεση ενός κακού task | git stash και ό,τι βγει | Καμία | choragos rollback T3 |
| Ορατότητα κόστους | Καμία | Ανά session, στο UI του vendor | Ανά ρόλο, live, από το gateway |
| Compliance path | Κανένα | Το endpoint του vendor | Τοπικό gateway, fail-closed |
Με δυο λόγια: οι subagents είναι η σωστή απάντηση όταν ο agent ενός vendor μπορεί να βγάλει όλη τη δουλειά σε ένα context. Το Choragos είναι η σωστή απάντηση όταν η δουλειά θέλει διαφορετικές θέσεις με διαφορετικά μοντέλα, διαφορετικά privileges, και ένα αρχείο του ποιος έκανε τι.
Τι ΔΕΝ είναι το Choragos#
- Δεν είναι agent. Δεν μιλάει το ίδιο με κανένα μοντέλο. Τρέχει τα CLIs που έχεις ήδη.
- Δεν είναι terminal multiplexer. Δεν θα αντικαταστήσει το tmux για τα shells σου. Διαχειρίζεται panes με agents και τίποτα άλλο.
- Δεν είναι CI σύστημα. Η δουλειά ανατίθεται live, σε ένα session στο οποίο μπορείς να κάνεις attach, δεν μπαίνει σε ουρά μέσα σε pipeline.
- Δεν είναι wrapper πάνω από το SDK κάποιου vendor. Δεν υπάρχουν provider hooks. Το token telemetry βγαίνει από όσα βλέπει το gateway στο wire.
- Δεν είναι sandbox. Το
env_denyκρατάει τα credentials έξω από το environment ενός ρόλου. Δεν εμποδίζει έναν agent να διαβάσει αρχεία ή να τρέξει εντολές στο shell.
Βασικές έννοιες#
Το μοντέλο της ομάδας#
Ένας ρόλος είναι μια θέση, και το config file είναι το οργανόγραμμα. Κάθε θέση δηλώνει το binary που θα τρέξει, το μοντέλο με το οποίο θα το τρέξει, ένα prompt_template που γίνεται το μόνιμο brief της, και το scope όσων επιτρέπεται να βλέπει.
Ακριβώς μία θέση έχει start = true. Αυτή είναι ο orchestrator: παίρνει το πρωτόκολλο του delegation μέσα στο boot brief του και δέχεται πίσω τα reports του work-done. Όλοι οι άλλοι είναι workers που περιμένουν ένα task.
Ο λόγος που αυτό κερδίζει έναν agent με ένα μακρύ prompt είναι το context, όχι ο παραλληλισμός. Κάθε worker είναι ξεχωριστό process με ξεχωριστό context window, οπότε ο reviewer δεν βλέπει ποτέ την εξερεύνηση του coder, ο auditor δεν βλέπει ποτέ το πρόχειρο του reviewer, και κανείς τους δεν κληρονομεί το πλάνο του orchestrator. Όταν μοιράζεις το correctness και το security σε δύο θέσεις, παίρνεις αισθητά καλύτερα ευρήματα από το να ζητήσεις και τα δύο από έναν agent, γιατί κανένα από τα δύο reviews δεν χρειάζεται να ανταγωνιστεί το άλλο για προσοχή μέσα στο ίδιο context.
Το teams doc έχει τα νούμερα πίσω από το άλλο μισό αυτού του επιχειρήματος: το system prompt του Claude Code είναι γύρω στα 44k tokens, τα προσωπικά σου MCP servers προσθέτουν περίπου 25k, ένα global CLAUDE.md άλλα 10k, ενώ το boot brief του Choragos κοστίζει γύρω στο 1.5k. Αν αφαιρέσεις τα MCP servers από τους workers με το --strict-mcp-config, μια περίπτωση που μετρήθηκε πέφτει από περίπου 42% του context καταναλωμένο στο boot σε περίπου 30%. Οι workers δεν χρειάζονται το Jira MCP σου. Ο orchestrator ίσως.
Ξεχωριστά processes σημαίνει και ξεχωριστά privileges, και αυτό είναι το κομμάτι που δεν έχει αντίστοιχο μέσα σε έναν μόνο agent. Το env_allow γυρίζει μια θέση από το «κληρονομώ τα πάντα» σε allowlist. Το env_deny αφαιρεί συγκεκριμένες μεταβλητές και υπερισχύει πάντα έναντι ενός allow. Ένας reviewer που μόνο διαβάζει κώδικα δεν έχει κανέναν λόγο να κρατάει AWS_*, και εδώ απλώς δεν τα έχει.
Το πρωτόκολλο delegate/work-done#
Ο agent του orchestrator δεν έχει κάποιο ειδικό κανάλι. Το boot brief του τού λέει ότι μπορεί να τρέχει shell commands, και αυτά τα commands είναι τα choragos delegate και choragos work-done. Και τα δύο συνδέονται σε ένα Unix socket στο $CHORAGOS_SOCK, που το deck το περνάει στο environment κάθε ρόλου.
# what the orchestrator agent runs
choragos delegate --to coder --task "Add retry with jitter to the S3 client" \
--brief "See internal/store/s3.go. Existing backoff is linear."
# what the worker runs when it is finished
choragos work-done --id T3 --done \
--task "Added exponential backoff with jitter" \
--report .choragos/reports/T3.md
Το socket είναι ένα ανά directory: <runtime dir>/choragos-<uid>/<8 hex of sha256(cwd)>.sock, mode 0600, με deadline πέντε δευτερολέπτων για ολόκληρη την ανταλλαγή. Το hash του directory κόβεται τόσο απότομα επειδή τα paths των Unix sockets έχουν όριο κοντά στα 104 bytes στο macOS.
Το wire contract είναι αρκετά μικρό ώστε να το υλοποιήσεις από οποιαδήποτε γλώσσα:
{
"cmd": "delegate",
"to": ["coder"],
"task": "Add retry with jitter to the S3 client",
"brief": "See internal/store/s3.go. Existing backoff is linear."
}
Το ack είναι {"status":"ok"}, και τα docs το λένε ρητά: σημαίνει παραδόθηκε στο deck, όχι το αποδέχτηκε ο agent. Η διάκριση μετράει όταν κάνεις integration: τίποτα στην ανταλλαγή πάνω από το socket δεν σου λέει ότι το μοντέλο έκανε τη δουλειά.
Όταν φτάνει ένα delegation, το deck τού δίνει ένα task id (T1, T2, …), παίρνει checkpoint του workspace, γράφει το task file και κάνει inject στο pane του παραλήπτη τη γραμμή που δείχνει σε αυτό. Όταν γυρίσει το work-done, η περίληψη γίνεται inject στο pane του orchestrator ως A worker reports: ... και η εγγραφή στο board κλείνει.
Approval gates και checkpoints#
Δύο διαφορετικά δίχτυα ασφαλείας, σε δύο διαφορετικές στιγμές.
Το gate ενεργοποιείται πριν από τη δουλειά: βάλε approve = true σε έναν ρόλο και κάθε delegation προς αυτόν σταματάει στο deck μέχρι να πατήσεις y ή n. Μπορείς να διαβάσεις το brief μέσα στην εφαρμογή με v, ή να το ανοίξεις στον $EDITOR με e. Η απόρριψη αναφέρεται πίσω στον orchestrator, και αυτό είναι που το κάνει χρήσιμο, γιατί ο orchestrator μπορεί να ξανασχεδιάσει αντί να μείνει κρεμασμένος.
Το checkpoint ενεργοποιείται αφού διαπιστώσεις ότι κάτι πήγε στραβά. Κάθε delegation παίρνει snapshot των tracked και των untracked αρχείων (σεβόμενο το .gitignore) ως commit χωρίς parent, κάτω από το refs/choragos/checkpoints/<epoch>-<task-id>. Το index σου, το HEAD, τα branches και το stash δεν τα αγγίζει ποτέ, και κανένα porcelain command δεν θα σου δείξει ποτέ αυτά τα commits.
choragos checkpoints # task id, age, target role
choragos rollback T3 # restore files to the state before T3 ran
choragos checkpoints prune # apply the retention policy (default: keep 20)
Το rollback επαναφέρει αρχεία και σβήνει όσα δημιούργησε το task. Δεν μετακινεί ποτέ το HEAD και δεν ξαναγράφει history, και πριν κάνει οτιδήποτε παίρνει checkpoint της τρέχουσας κατάστασης, οπότε το choragos rollback pre-rollback-T3 αναιρεί την αναίρεση.
Γιατί έχει σημασία: με παράλληλους agents, αυτό που πάει στραβά δεν είναι ένα θεαματικό λάθος, είναι ένας worker που ξαναγράφει αθόρυβα ένα αρχείο το οποίο ένας άλλος worker είχε αφήσει στη μέση. Το να μπορείς να ονομάσεις το task και να επαναφέρεις ακριβώς το δικό του blast radius αξίζει περισσότερο από ένα
git stashπου πρέπει να ανασυνθέσεις από μνήμης.
Owned PTY panes, και γιατί το handoff δεν έχει race#
Όλα τα παραπάνω είναι ένα μοντέλο συντονισμού, και ένα μοντέλο συντονισμού αξίζει όσο και η παράδοση των μηνυμάτων του. Αυτό είναι το άχαρο layer που κάνει τα υπόλοιπα αξιόπιστα.
Ο προφανής τρόπος να το φτιάξεις είναι ένας agent ανά tmux pane, που τον οδηγείς με send-keys και κάνεις polling στο κείμενο του pane για να καταλάβεις πότε ο agent είναι έτοιμος για την επόμενη εντολή. Αυτό έφτιαξα πρώτα. Δουλεύει, μέχρι τη στιγμή που το TUI ενός agent ξαναζωγραφίζει τη status line του τη λάθος στιγμή, το send-keys πέφτει σε ένα pane που δεν έχει τελειώσει το boot, και η μισή εντολή καταλήγει ως σκέτο κείμενο σε ένα prompt που δεν γίνεται ποτέ submit. Κάνεις polling σε μια οθόνη που σου λέει ψέματα.
Το Choragos, αντίθετα, ξεκινάει κάθε agent με pty.StartWithSize και περνάει το output από έναν emulator hinshun/vt10x, οπότε κρατάει το πραγματικό screen buffer και όχι ένα scrape του. Έτσι ξέρει αν ένας agent περιμένει input, αν δουλεύει ή αν είναι idle, και γι’ αυτό το boot injection επαληθεύεται αντί να γίνεται στα τυφλά: περίμενε ένα δευτερόλεπτο μετά την εκκίνηση, περίμενε 1200ms χωρίς output, κάνε inject το brief του ρόλου, και μετά έλεγξε την οθόνη για να επιβεβαιώσεις ότι το κείμενο έφτασε. Αν δεν έφτασε, ξαναδοκίμασε μετά από τρία δευτερόλεπτα, μέχρι δύο προσπάθειες.
Μια λεπτομέρεια εκεί μέσα αξίζει ξεχωριστή αναφορά, γιατί πήρε καιρό να βρεθεί:
// injectEnterDelay separates the typed text from its submit;
// Claude's TUI treats text+Enter in one write as a paste.
const injectEnterDelay = 200 * time.Millisecond
Αν γράψεις το κείμενο και το carriage return σε ένα μόνο PTY write, το Claude Code το αντιμετωπίζει σαν paste, που καταλήγει στο input box χωρίς να γίνει submit. Αν χωρίσεις το write με 200ms ανάμεσα, γίνεται πληκτρολόγηση. Αυτή είναι η κατηγορία bug που κάνει τα scripts πάνω σε multiplexer flaky, και δεν διορθώνεται έξω από το terminal.
Ο ίδιος περιορισμός εξηγεί γιατί το περιεχόμενο ενός task ταξιδεύει ως αρχείο και όχι ως injected κείμενο: τα multi-line pastes χάνονται. Ένα delegation γράφει το .choragos/worker-task-<role>.md και κάνει inject μία μόνο γραμμή που λέει στον worker να το διαβάσει.
Αρχιτεκτονική#
flowchart TB
User([You]) -->|attach / keys| Deck
subgraph Deck["Choragos Deck"]
TUI[Tiling WM + task board]
Core[Session core: roster, PTYs, gates]
Sock[(Unix socket 0600)]
end
subgraph Panes["Owned PTY panes"]
Orch[orchestrator]
Coder[coder]
Rev[reviewer]
Aud[auditor]
end
Core -->|PTY write| Orch
Core -->|PTY write| Coder
Core -->|PTY write| Rev
Core -->|PTY write| Aud
Orch -->|choragos delegate| Sock
Coder -->|choragos work-done| Sock
Rev -->|choragos work-done| Sock
Sock --> Core
Core -->|snapshot| Git[(refs/choragos/checkpoints)]
Orch -.->|ANTHROPIC_BASE_URL| GW
Coder -.->|/agent/coder| GW
Rev -.->|/agent/reviewer| GW
GW[Sphragis gateway] -.->|redacted| API[Model provider]
GW -.->|/metrics| Core
Το session core δεν έχει καθόλου UI, και αυτό είναι σκόπιμο. Το internal/deck/session.go κρατάει το roster, τα PTYs, τα tasks, τα gates, το IPC και το supervision χωρίς κανένα import από bubbletea ή lipgloss, και μιλάει με το UI μέσα από ένα notify channel. Αυτός ο διαχωρισμός είναι που επέτρεψε το headless mode και το detach/attach χωρίς rewrite.
Συνταγές configuration#
Το Choragos διαβάζει το .choragos.toml από το working directory. Αν δεν υπάρχει, τρέχει μια built-in ομάδα πέντε ρόλων. Τα άγνωστα keys γίνονται warnings στην εκκίνηση αντί να αγνοούνται σιωπηλά, κάτι που εκτιμώ όλο και περισσότερο κάθε φορά που γράφω λάθος ένα key.
Φτιάξε ένα με το choragos init, ή διάλεξε ένα template:
choragos init # commented starter
choragos init --template review # read-only review crew
choragos init --template claude-team # all-Claude
choragos init --template mixed-team # Claude + a Gemini CLI
choragos init --auto # detect go.mod/package.json/Cargo.toml/pyproject.toml
choragos doctor # check the setup before you start
Παρακάτω είναι τα configs που τρέχω στην πράξη, ένα ανά use case.
Συνταγή 1: η default τριάδα#
Σχεδιασμός, υλοποίηση, review. Αυτό γράφει το choragos init, και είναι το σωστό σημείο εκκίνησης σχεδόν για όλους.
[[roles]]
name = "orchestrator"
command = "claude"
model = "opus"
start = true
prompt_template = "You coordinate the team. Plan and delegate only; never implement, review, or audit yourself."
[[roles]]
name = "coder"
command = "claude"
model = "opus"
# workers skip your personal MCP servers (context hygiene); delete to inherit them
args = ["--strict-mcp-config"]
prompt_template = "Implement the requested change. Run the project's tests before reporting done."
[[roles]]
name = "reviewer"
command = "claude"
model = "sonnet"
args = ["--strict-mcp-config"]
prompt_template = "Review the change for correctness and edge cases. Report findings only; do not modify code."
# the reviewer never needs your cloud credentials
env_deny = ["AWS_*", "GCP_*", "GITHUB_TOKEN"]
Ακριβώς ένας ρόλος έχει start = true. Αυτός ο ρόλος είναι ο orchestrator: παίρνει το πρωτόκολλο του delegation μέσα στο boot brief του και δέχεται τα reports του work-done.
Το --strict-mcp-config στους workers είναι ο μοχλός για το context hygiene που είδαμε στην ενότητα με το μοντέλο της ομάδας: οι workers ξεκινούν χωρίς τα προσωπικά σου MCP servers, οπότε μένει περισσότερο από το window τους για το task που ανέθεσες. Σβήσ’ το αν ένας worker χρειάζεται πραγματικά κάποιο από αυτά.
Αποτέλεσμα: τρία panes, ένας που σχεδιάζει, ένας coder με τα credentials σου, ένας reviewer χωρίς αυτά.
Συνταγή 2: read-only ομάδα για review#
Κανένας ρόλος σε αυτή την ομάδα δεν επιτρέπεται να γράψει κώδικα. Την τρέχω πάνω σε ένα branch πριν βγει το PR, και είναι το config που θα έδινα σε κάποιον που αγχώνεται με την ιδέα ότι agents αγγίζουν το repo του.
[[roles]]
name = "orchestrator"
command = "claude"
model = "opus"
start = true
prompt_template = "You coordinate a read-only review. Split the work into correctness and security aspects, delegate, then merge the findings into one report. Never modify code."
[[roles]]
name = "reviewer"
command = "claude"
model = "opus"
args = ["--strict-mcp-config"]
prompt_template = "Review the change for correctness, edge cases, and maintainability. Report findings only; do not modify code."
[[roles]]
name = "auditor"
command = "claude"
model = "sonnet"
args = ["--strict-mcp-config"]
prompt_template = "Audit the change for security issues: injection, secret handling, unsafe defaults, dependency risk. Report findings only; do not modify code."
env_deny = ["AWS_*", "GCP_*", "GITHUB_TOKEN"]
[checkpoints]
enabled = false # nothing writes; skip the snapshots
Αποτέλεσμα: δύο ανεξάρτητα reviews με ξεχωριστά contexts, που ο orchestrator τα ενώνει σε ένα report. Όταν μοιράζεις το correctness και το security σε δύο θέσεις, παίρνεις αισθητά καλύτερα ευρήματα από το να ζητήσεις και τα δύο από έναν agent, γιατί κανένα από τα δύο reviews δεν χρειάζεται να ανταγωνιστεί το άλλο για προσοχή μέσα στο ίδιο context.
Συνταγή 3: διαφορετικοί vendors, least privilege#
Το σύστημα των ρόλων δεν ενδιαφέρεται για το ποιον vendor χρησιμοποιείς. Το command είναι οποιοδήποτε binary στο PATH, και το model προστίθεται στο τέλος ως --model <value>, μια σύμβαση που τυχαίνει να ταιριάζει στα περισσότερα agent CLIs. Εδώ το Claude υλοποιεί και ένα Gemini CLI κάνει review, οπότε ο reviewer είναι πραγματικά μια δεύτερη γνώμη και όχι το ίδιο μοντέλο που βαθμολογεί το δικό του γραπτό.
[[roles]]
name = "orchestrator"
command = "claude"
model = "opus"
start = true
prompt_template = "You coordinate the team. Plan and delegate only; never implement, review, or audit yourself."
[[roles]]
name = "coder"
command = "claude"
model = "opus"
args = ["--strict-mcp-config"]
prompt_template = "Implement the requested change. Run the project's tests before reporting done."
env_allow = ["ANTHROPIC_API_KEY"]
[[roles]]
name = "reviewer"
command = "agy"
model = "Gemini 3.1 Pro (High)"
prompt_template = "Review the change for correctness and edge cases. Report findings only; do not modify code."
env_allow = ["GEMINI_API_KEY", "GOOGLE_*"]
# teach the status heuristics this TUI's prompts if they differ from Claude's
input_prompts = ["continue? <enter>"]
chrome_markers = ["agy statusbar"]
Δύο πράγματα πρέπει να καταλάβεις για το μοντέλο του env. Όταν ορίζεις env_allow, ο ρόλος αυτός περνάει από το «κληρονομώ τα πάντα» σε allowlist: οι βασικές μεταβλητές (PATH, HOME, TERM, SHELL, LANG, LC_*, XDG_* και οι συγγενείς τους) συν ακριβώς όσα αναφέρεις. Τα wildcards είναι μόνο prefix (GOOGLE_*), και το env_deny εφαρμόζεται πρώτο, οπότε ένα deny κερδίζει πάντα ένα allow.
Τα input_prompts και chrome_markers είναι η έξοδος κινδύνου για TUIs που δεν είναι του Claude: το πρώτο μαθαίνει στο readiness heuristic πώς μοιάζει το «αυτός ο agent έχει κολλήσει περιμένοντας input», το δεύτερο λέει στο sidebar ποιες γραμμές είναι chrome και δεν πρέπει να εμφανίζονται στο activity preview.
Αποτέλεσμα: κάθε API key υπάρχει μόνο στο process που το χρειάζεται. Ο Gemini reviewer σου δεν βλέπει το ANTHROPIC_API_KEY, και κανένας από τους δύο δεν βλέπει τα cloud credentials σου.
Συνταγή 4: regulated, με υποχρεωτικό gateway#
Αυτό είναι το config για την περίπτωση για την οποία φτιάχτηκε στην πραγματικότητα το Choragos: κάθε prompt που στέλνει ένας agent πρέπει να περνάει από ένα gateway μέσα στο δικό σου trust boundary, και αν το gateway δεν είναι εκεί, δεν γίνεται καμία δουλειά.
[[roles]]
name = "orchestrator"
command = "claude"
model = "opus"
start = true
prompt_template = "You coordinate the team. Plan and delegate only; never implement, review, or audit yourself."
[[roles]]
name = "coder"
command = "claude"
model = "opus"
args = ["--strict-mcp-config"]
prompt_template = "Implement the requested change. Run the project's tests before reporting done."
[[roles]]
name = "release"
command = "claude"
model = "haiku"
args = ["--strict-mcp-config"]
prompt_template = "Run the release flow only after explicit human sign-off. Never push without approval."
approve = true # every delegation here waits for y/n
env_deny = ["AWS_*", "GCP_*"]
[sphragis]
enabled = true # explicit: require the gateway
fail_closed = true # refuse delegation while it is down
addr = "127.0.0.1:8787"
[pricing."claude-opus-4-8"]
input = 5.0
output = 25.0
cache_read = 0.5
cache_creation = 6.25
[pricing."claude-haiku-4-5"]
input = 1.0
output = 5.0
cache_read = 0.1
cache_creation = 1.25
Γράψε το enabled = true ρητά. Το default είναι επίτηδες χαλαρό: αν δεν αναφέρεις πουθενά το gateway, το binary δεν υπάρχει στο PATH και τίποτα δεν ακούει στο addr, το deck ξεκινάει με το gateway κλειστό και γράφει ένα warning αντί να αρνηθεί να τρέξει. Αυτό είναι φιλικό για μια πρώτη εγκατάσταση και λάθος για μια regulated. Το να γράψεις το key είναι αυτό που ενεργοποιεί την εγγύηση του fail-closed.
Με fail_closed = true, το dispatch απορρίπτει κάθε command όσο το gateway δεν είναι healthy και γράφει στο log dispatch refused: gateway down. Το μόνο verb που εξαιρείται είναι το reload, με το σκεπτικό ότι το reload αλλάζει την ομάδα, όχι τη δουλειά.
Αποτέλεσμα: κανένας agent σε αυτό το session δεν μπορεί να φτάσει σε model provider παρά μόνο μέσα από ένα gateway που τρέχεις εσύ, και το deck σταματάει να μοιράζει δουλειά τη στιγμή που αυτό πάψει να ισχύει.
Συνταγή 5: long-running και χωρίς επίβλεψη#
Τα sessions κάνουν detach όπως στο tmux. Το πρόβλημα με ένα session χωρίς επίβλεψη δεν είναι το detach, είναι ότι ένας worker μπορεί να κολλήσει σε ένα loop στις τρεις τα ξημερώματα και να μη σου το πει τίποτα.
[[roles]]
name = "orchestrator"
command = "claude"
model = "opus"
start = true
prompt_template = "You coordinate the team. Plan and delegate only; never implement, review, or audit yourself."
[[roles]]
name = "coder"
command = "claude"
model = "opus"
args = ["--strict-mcp-config"]
prompt_template = "Implement the requested change. Run the project's tests before reporting done."
timeout = "45m" # wall clock per delegation
timeout_action = "restart" # SIGTERM the role; restart takes over
restart = "on-failure"
restart_retries = 3
[ui]
bell = true
# hooks inherit the `choragos serve` environment; keep webhook URLs out of this file
on_gate = 'curl -sf -d "$CHORAGOS_ROLE awaits approval: $CHORAGOS_TASK" "ntfy.sh/$NTFY_TOPIC"'
on_input = 'curl -sf -d "$CHORAGOS_ROLE is waiting for input" "ntfy.sh/$NTFY_TOPIC"'
on_timeout = 'curl -sf -d "$CHORAGOS_ROLE timed out on: $CHORAGOS_TASK" "ntfy.sh/$NTFY_TOPIC"'
Το ρολόι του timeout ξεκινάει όταν το task παραδοθεί, δηλαδή μετά από όποιο approval gate, οπότε ένα task που περιμένει στην ουρά των εγκρίσεών σου δεν καίει το budget του. Το timeout_action = "notify" χτυπάει το bell, σημειώνει το board, τρέχει το hook και αφήνει τον worker να συνεχίσει. Το restart σκοτώνει τον ρόλο και αφήνει το restart budget να τον ξαναξεκινήσει. Το budget του restart_retries υπάρχει για να μην μπορεί ένα πραγματικά χαλασμένο command να μπει σε crash loop, και ένα χειροκίνητο prefix+R το μηδενίζει.
Μετά τρέξ’ το headless:
choragos serve --detach # double-forks, setsid, logs to .choragos/logs/server.log
choragos ls # sessions across projects
choragos attach # TUI back, with scrollback, board, gates and layout restored
choragos kill --all
Το prefix+d κάνει detach μέσα από το deck. Μόνο ένας client μπορεί να είναι attached κάθε φορά. Ένα δεύτερο choragos attach απορρίπτεται και σου λέει ποιο pid το κρατάει.
Αποτέλεσμα: η ομάδα συνεχίζει να δουλεύει αφού κλείσεις το καπάκι του laptop, και το κινητό σου δονείται όταν σε χρειαστεί.
Telemetry, και τι σου δίνει το report#
Με το gateway στο path, κάθε ρόλος ξεκινάει με το ANTHROPIC_BASE_URL να δείχνει στο http://<addr>/agent/<role>. Αυτό το suffix ανά ρόλο στο path είναι όλος ο μηχανισμός του attribution: το gateway μετράει tokens ανά agent, και το Choragos τα παίρνει πίσω με scrape από το Prometheus endpoint του gateway. Ένα regex είναι όλο το συμβόλαιο:
var tokenLine = regexp.MustCompile(
`^sphragis_tokens_total\{agent="([^"]*)",model="([^"]*)",direction="([^"]*)"\} ([0-9.eE+]+)$`)
Γίνονται parse τέσσερα directions (input, output, cache_creation, cache_read), το fetch έχει timeout ενός δευτερολέπτου με όριο 1 MiB στο body, και τα αθροιστικά snapshots γράφονται στο event log κάθε 30 δευτερόλεπτα και στην έξοδο. Το κόστος είναι απλώς tokens * price_per_mtok / 1e6 με βάση τον πίνακα [pricing] σου, και κερδίζει το μακρύτερο prefix που ταιριάζει στο όνομα του μοντέλου. Οι κάρτες στο sidebar δείχνουν ↑in ↓out $cost, και τα ποσά κάτω από ένα cent εμφανίζονται με τέσσερα δεκαδικά, για να μη φαίνεται ένα φτηνό run ως $0.00.
Ούτε SDK hooks, ούτε instrumentation από τον vendor. Το gateway μετράει ό,τι αναφέρει ο provider.
Μετά από ένα run, το choragos report κάνει parse το event log και τυπώνει έναν πίνακα ανά ρόλο:
run 2026-07-18 09:14:22 · wall 1h12m · /Users/nn/git/myservice
ROLE TASKS DONE BUSY AVG FIRST LAST TOKENS
orchestrator - - - - 09:14:31 10:26:04 184.2k
coder 6 6 52m18s 8m43s 09:16:02 10:21:37 1.4M
reviewer 6 5 31m04s 6m12s 09:23:11 10:24:50 612.9k
auditor 2 2 9m47s 4m53s 09:58:20 10:19:02 203.1k
1 task(s) never reported work-done
Αυτή η τελευταία γραμμή είναι η πρώτη που κοιτάζω. Ένα task που δεν ανέφερε ποτέ πίσω είναι είτε ένας worker που τελείωσε και ξέχασε να καλέσει το work-done, είτε ένας που πέθανε αθόρυβα. Και τα δύο αξίζει να τα ξέρεις πριν εμπιστευτείς το diff.
Εγκατάσταση και quick start#
# macOS / Linux
brew install sphragis-oss/sphragis/choragos
# native macOS app with the CLI bundled
brew install --cask sphragis-oss/sphragis/choragos-desktop
# from source (Go 1.26+)
git clone https://github.com/sphragis-oss/choragos.git
cd choragos && make build
Πρώτο run:
cd ~/git/your-project
choragos init --auto # detects the project, writes language-specific roles
choragos doctor # verifies binaries, socket path, git repo, gateway
choragos serve
Θέλεις να δεις το deck πριν του δώσεις πραγματικούς agents; Το make demo τρέχει πέντε placeholder panes με το gateway κλειστό, χρησιμοποιώντας το examples/demo.toml, όπου κάθε ρόλος είναι ένα σκέτο sh -c που τυπώνει ένα banner και κάνει exec cat. Είναι ο φθηνότερος τρόπος να μάθεις το keymap.
Το deck το χειρίζεσαι όπως το tmux, πίσω από ένα prefix key (default ctrl+b):
| Binding | Ενέργεια |
|---|---|
prefix + v / - | Split κάθετα / οριζόντια |
prefix + h j k l | Μετακίνηση του focus, το 1..9 πηγαίνει κατευθείαν σε έναν ρόλο |
prefix + z | Zoom στο tile που έχει το focus |
prefix + t | Task board |
prefix + R | Restart του ρόλου που έχει το focus |
prefix + p | Pause / resume ενός ρόλου (SIGSTOP / SIGCONT) |
prefix + a | Broadcast του input σε όλους τους agents |
prefix + C | Reload του config |
prefix + d | Detach |
prefix + / | Αναζήτηση στο scrollback |
ctrl+g | Αλλαγή του gateway enforcement live |
Το κλείσιμο ενός tile δεν σκοτώνει ποτέ τον agent του. Μου πήρε καιρό να σταματήσω να τινάζομαι κάθε φορά.
Το prefix + p είναι το υποτιμημένο: παγώνοντας έναν ρόλο εν κινήσει, διαβάζεις τι κάνει χωρίς να σου φεύγει μπροστά, και με το resume το context του agent μένει άθικτο. Είναι όμως best-effort, και τα docs το λένε: τα children που έχουν δικό τους process group συνεχίζουν να τρέχουν, και ένα API call που βρίσκεται σε εξέλιξη κατά τη διάρκεια ενός μεγάλου pause μπορεί να κοπεί και να ξαναγίνει στο resume.
Αλλαγές στην ομάδα χωρίς restart#
Άλλαξε το .choragos.toml και μετά τρέξε choragos reload ή πάτα prefix+C. Το deck ξαναδιαβάζει το αρχείο και συγκλίνει την ομάδα που τρέχει με βάση το όνομα του ρόλου: οι ρόλοι που προστέθηκαν ξεκινούν και παίρνουν το boot brief τους, όσοι αφαιρέθηκαν σταματούν ομαλά, μια αλλαγή σε command/args/model/env_* ξαναξεκινάει τον συγκεκριμένο ρόλο, και οι αλλαγές σε prompt_template/approve/restart* ισχύουν από το επόμενο task, χωρίς restart.
Τα guardrails μετράνε περισσότερο από το ίδιο το feature:
- Το process του start role δεν το αγγίζει ποτέ. Οι αλλαγές στο spec του και η αφαίρεσή του αγνοούνται μέχρι το επόμενο restart του deck, γιατί αν σκοτώσεις τον orchestrator στη μέση του session χάνεις το πλάνο.
- Ένας ρόλος με gate σε εκκρεμότητα ή με delegation που δεν έχει κλείσει δεν ξαναξεκινάει. Κλείσε τη δουλειά και κάνε πάλι reload.
- Στη built-in ομάδα (χωρίς config file) δεν υπάρχει τίποτα να ξαναδιαβαστεί, οπότε το reload απορρίπτεται.
- Μόνο το
[[roles]]συγκλίνει live. Οι αλλαγές σε[keys],[ui]και[sphragis]θέλουν restart.
Troubleshooting#
| Πρόβλημα | Σύμπτωμα | Λύση |
|---|---|---|
| Ο ρόλος δεν ξεκινάει | command not found στο boot | Το command πρέπει να είναι πραγματικό binary στο PATH, τα shell aliases δεν γίνονται resolve. Τρέξε choragos doctor |
| Πολύ μακρύ socket path | Το doctor αποτυγχάνει στον έλεγχο του socket | Το macOS βάζει όριο στο sun_path κοντά στα 104 bytes. Βάλε στο CHORAGOS_SOCK ένα σύντομο path, ή δούλεψε από πιο σύντομο directory |
| Το delegation απορρίπτεται | dispatch refused: gateway down στο events.log | Το gateway δεν είναι healthy και ισχύει fail_closed = true. Ξεκίνα το Sphragis, ή άλλαξε το enforcement με ctrl+g |
| Ένα key του config αγνοείται | Warning εκκίνησης στο events.log | Άγνωστο key, συνήθως τυπογραφικό. Τα warnings δεν είναι ποτέ σιωπηλά, οπότε διάβασέ τα |
| Το scrollback φαίνεται άδειο | Ένα full-screen TUI ενός agent δείχνει μόνο το τελευταίο του frame | Αναμενόμενο. Τα full-screen TUIs ξαναζωγραφίζουν στο ίδιο σημείο και δεν στέλνουν ποτέ το παλιό περιεχόμενο στο PTY, οπότε το ιστορικό δεν υπήρξε ποτέ στο byte stream |
| Οι μετρητές των tokens μηδενίζονται | Οι κάρτες πέφτουν στο μηδέν στη μέση του session | Το gateway έκανε restart. Οι μετρητές είναι του gateway, όχι του deck |
| Το δεύτερο attach απορρίπτεται | Error που αναφέρει ένα pid | Ένας client κάθε φορά, by design. Σκότωσε αυτόν που το κρατάει ή κάν’ του detach |
Αυτό με το transcript αξίζει μια πρόταση, γιατί μοιάζει με bug και δεν είναι. Αν ένας agent τρέχει full-screen TUI, το «transcript» του είναι μόνο ό,τι υπήρχε τελευταίο στην οθόνη, όση ώρα κι αν κράτησε το session. Δεν χάθηκε κάτι στο capture. Η αφήγηση δεν υπήρξε ποτέ στο byte stream για να γίνει capture.
Choragos: υπέρ και κατά#
Υπέρ#
| Πλεονέκτημα | Περιγραφή |
|---|---|
| Πραγματικό readiness detection | Επειδή το PTY είναι δικό του και το κάνει parse, εξαφανίζονται τα boot races που κάνουν τα scripts πάνω σε multiplexer flaky |
| Ρόλοι ανεξάρτητοι από vendor | Οποιοδήποτε binary στο PATH είναι έγκυρη θέση, και μπορείς να έχεις Claude και Gemini στην ίδια ομάδα |
| Least privilege ανά θέση | Τα env_allow / env_deny κρατούν τα credentials μακριά από ρόλους που δεν έχουν λόγο να τα κρατάνε |
| Αναίρεση με το σωστό blast radius | Τα checkpoints είναι ανά delegation και δεν αγγίζουν ποτέ το HEAD, το index ή το history |
| Κόστος που το βλέπεις | Live tokens και δολάρια ανά ρόλο, συν ένα report μετά το run, χωρίς κανένα SDK integration |
| Το compliance path είναι πραγματικό | Fail-closed enforcement του gateway, όχι ένα σχόλιο στο config που δεν ελέγχει κανείς |
| Μικρή επιφάνεια dependencies | Οκτώ άμεσα Go dependencies, ~6.4k γραμμές production Go απέναντι σε ~5.6k γραμμές tests, 180 tests, CI με race detector, govulncheck, CodeQL, zizmor και SHA-pinned actions |
Κατά#
| Περιορισμός | Περιγραφή |
|---|---|
| Terminal-first | Υπάρχει desktop app για macOS, αλλά το νοητικό μοντέλο παραμένει panes και ένα prefix key |
| Gateway path κομμένο στα μέτρα της Anthropic | Το routing ανά ρόλο δουλεύει μέσω του ANTHROPIC_BASE_URL, οπότε ένα CLI που δεν είναι της Anthropic είναι first-class ρόλος αλλά όχι first-class gateway client |
| Ένας attached client | Ούτε multi-client attach, ούτε remote attach, ούτε live migration ανάμεσα σε διαφορετικές εκδόσεις |
| Το reload είναι μερικό | Μόνο το [[roles]] συγκλίνει live, ενώ τα keys, το UI και οι ρυθμίσεις του gateway θέλουν restart |
| Τα checkpoints θέλουν git | Σε directory χωρίς git το deck βγάζει warning και τρέχει απροστάτευτο |
| Το pause είναι best-effort | Το SIGSTOP δεν φτάνει στα children που έχουν δικό τους process group |
| Νεαρό project | v0.11.2, ένας maintainer, το API και η επιφάνεια του config αλλάζουν ακόμα |
Πότε να το χρησιμοποιήσεις, και πότε όχι#
Χρησιμοποίησε το Choragos όταν:
- Τρέχεις ήδη δύο ή περισσότερους agents ταυτόχρονα και κουβαλάς με το χέρι το context από τον έναν στον άλλον
- Θέλεις διαφορετικό vendor ή μοντέλο ανά θέση, και ειδικά έναν reviewer που δεν είναι το ίδιο μοντέλο με τον coder
- Διαφορετικές θέσεις πρέπει να έχουν διαφορετικά credentials
- Χρειάζεσαι ένα αρχείο του τι έκαναν οι agents και πόσο κόστισε, και έναν τρόπο να αναιρέσεις καθαρά ένα task
- Βρίσκεσαι σε περιβάλλον όπου κάθε prompt πρέπει να περνάει από ένα gateway που ελέγχεις εσύ
Μη χρησιμοποιήσεις το Choragos όταν:
- Ένας agent σε ένα παράθυρο πραγματικά αρκεί. Συνήθως αρκεί. Μη βάζεις orchestrator σε μια δουλειά που ένας agent την τελειώνει σε δέκα λεπτά
- Θέλεις πλήρως αυτόνομα runs χωρίς επίβλεψη και χωρίς human in the loop. Τα gates και οι εγκρίσεις είναι εδώ το ζητούμενο, όχι συμβιβασμός
- Χρειάζεσαι ένα hosted, multi-user control plane. Αυτό είναι ένα τοπικό binary για έναν operator
Δοκίμασέ το#
Το project είναι Apache 2.0 στο GitHub, και παρακάτω είναι τα docs που μου φάνηκαν πιο χρήσιμα:
- sphragis-oss/choragos - το repo, v0.11.2
- Configuration reference - κάθε key του
.choragos.toml - Στήσε τη δική σου ομάδα - ρόλοι, briefs και τα νούμερα για το context hygiene
- Control protocol - το wire contract του delegate/work-done, αν θέλεις να το οδηγήσεις από δικά σου εργαλεία
- Ο σχεδιασμός των checkpoints - γιατί τα gates μόνα τους δεν φτάνουν
brew install sphragis-oss/sphragis/choragos
cd ~/git/your-project
choragos init --auto && choragos doctor && choragos serve
Issues και PRs είναι ευπρόσδεκτα. Το project απαιτεί DCO sign-off σε κάθε commit.
Συμπέρασμα#
Ο λόγος που τα multi-agent setups διαλύονται δεν είναι ότι τα μοντέλα δεν είναι αρκετά καλά. Είναι ότι κανείς δεν αποφασίζει ποιος κάνει τι, και τίποτα δεν φέρνει πίσω το αποτέλεσμα, οπότε το layer του συντονισμού γίνεται ένας άνθρωπος, και οι άνθρωποι είναι αργοί, χάνουν πληροφορία στη διαδρομή, και στις 03:00 κοιμούνται.
Το Choragos απαντάει σε αυτό με μια ομάδα και όχι με ένα εργαλείο. Δήλωσε τις θέσεις και άσε μία από αυτές να κρατάει το πλάνο. Δώσε τους δύο verbs και ένα socket, ώστε το handoff να είναι ένα command και όχι copy-paste, και κάθε task να έχει ένα ID που μπορείς να δείξεις. Δώσε σε κάθε θέση το δικό της context και μόνο τα credentials που χρειάζεται, ώστε το review να είναι ανεξάρτητο και ο reviewer να μην μπορεί να αγγίξει το production. Βάλε gate στις θέσεις που μπορούν να κάνουν ζημιά, και πάρε snapshot πριν από κάθε task, ώστε ένα κακό delegation να σου κοστίσει ένα rollback και όχι ένα απόγευμα. Το ότι το PTY είναι δικό του είναι αυτό που κάνει όλα τα παραπάνω να φτάνουν αξιόπιστα στον προορισμό τους, αλλά αυτό είναι τα υδραυλικά, όχι η ουσία.
Το κομμάτι του compliance είναι αυτό που με νοιάζει περισσότερο, και είναι ο λόγος που το project ζει στο ίδιο org με το Sphragis. Αν οι agents σου πρόκειται να στέλνουν prompts για το codebase σου σε έναν model provider, αυτό το traffic πρέπει να περνάει από κάτι που τρέχεις εσύ, και ο orchestrator πρέπει να αρνείται να μοιράσει δουλειά όταν δεν περνάει. Το fail_closed = true είναι τέσσερις λέξεις που μετατρέπουν ένα policy document σε συμπεριφορά που επιβάλλεται.
Ξεκίνα με το choragos init και τη default τριάδα. Πρόσθεσε το gateway όταν χρειαστείς το audit trail, βάλε approve = true στις θέσεις που μπορούν να κάνουν ζημιά, και βάλε timeouts πριν κάνεις για πρώτη φορά detach και φύγεις. Με αυτή τη σειρά μου έχει βγει καλά.
Αν σου φάνηκε χρήσιμο, ίσως σε ενδιαφέρουν και τα σχετικά posts μου:
- Sphragis - Το EU AI Act compliance gateway που ελέγχεις πραγματικά εσύ
- Φτιάχνοντας έναν Kubernetes agent με το Google ADK για Go
- Βγάζοντας ένα Obsidian plugin με έναν coding agent

