Repository navigation
Releases: sting8k/piggery
Release list
v0.10.4
top's sidebar is now the selected row's Tail, drawn as turns, and its width follows a drag.
- Change:
top's sidebar has no Overview tab any more (it repeated the row) andtis gone. It is
the selected row's Tail; on a team's line, its gate's (Tail · lark (gate)). Above a rule, a head
says what the row does not: the task and a newer mail, the model where it can be changed (a click
on it, orM, opens the picker as before), who spawned it and whom it reports to, and when a
closed team closed. The log below is drawn as turns, a blank line between two: what came in at the
left edge (a prompt›, mailfrom lark …), what the participant did two cells in. A run of tool
calls is one line (• 4 tools · bash ×3, edit); the latest run, still going, is a tree of its
last calls; a result shows only when it failed; mail sent is one line (to lark …), at the left
edge like mail in; an older turn keeps what came in, its calls and what it gave back. This works
for interactive sessions' transcripts as well as workers' logs.piggery tailstill prints every
line. - New: drag the line between the list and the sidebar in
topto resize the sidebar; the width
is kept for the nexttop(#34).topalso draws faster: its colours are worked out once, not
on every frame. Thanks to @sting-lon. - Change: in
piggery tail, a call to piggery's send tool shows whom it went to and its body
(> piggery_send lead #3 done) instead of cutbody=… to=…, andread,editandwrite
show their path also when the harness names itfile_path(Claude) or passes a list ofpaths.
v0.10.3
On Windows, pi workers started through pi's own launcher no longer go gone about ten seconds after they start.
- Fix (Windows): a pi worker went gone about ten seconds after it was spawned, with its mail
unread and an empty tail, when pi'spi.cmdnames its script"%~dp0pi-launcher.js", with no
backslash after%~dp0(pi's launcher writes it so); piggery did not see through such a shim, so the worker ran under
cmd.exe, one process too deep, and the daemon refused it as a harness nested in a worker
(#32). Thanks to @sting-lon for the report, the diagnosis and the fix.
v0.10.2
A Codex worker is woken for mail that came as its turn ended, and cleanup removes closed teams it used to skip.
- Fix: a Codex worker could stay idle with unread mail. A mail that came in the moment between
the end of its turn and Codex reporting that turn over did not wake it, and once a turn had been
kept going 8 times for mail that came during it, this happened every time; the mail waited for
a newer one. The worker
is now woken once the turn is over (#26). - Fix: cleanup never removed a closed team in which a member had been given mail on an earlier
run of its process (piggery gcreported that the team had changed since the archive was
written, every time). Such teams are now removed.
v0.10.1
Mail is no longer lost or held back after an interrupted, failed or crashed turn on any harness, cleanup keeps mail its recipients have not read, a team member can no longer stop a person's session, and Claude Code sessions keep their participant across /clear, /branch and forks.
Before you upgrade:
- A template with a typo inside a role, its
spawnblock or a routing rule no longer founds a
team. An unknown key there, a role name the manifest does not have, or a limit below 1 is
refused with the reason (nonestill switches a limit off). An unknown top-level key is ignored
with a warning, so a template written for a newer piggery still runs. Teams already founded keep
their manifest as it was. Runpiggery checkto see what a template of yours would hit.
After upgrading, run piggery restart: the daemon updates the integrations it installed to pi 14,
omp 14, dsh 15 and opencode 12. Then restart the sessions that were open, or run /reload in pi.
Mail:
- Fix: in omp and dsh, mail that arrived at the very last step of a reply was taken as read before
the model saw it. If the next step or run was stopped (Esc,piggery abort, a failure), that mail
was lost. It is now taken as read only once a model turn that shows it ends, and comes again
otherwise (#15). - Fix: a Claude Code turn interrupted with Esc, at a permission prompt or by an SDK client (Paseo)
held back wakes and mail until the next prompt, and a permission prompt left with Esc kept the
session shown as awaiting permission. Claude sends no hook for an interrupt; piggery now reads
Claude's own session status and ends such a turn as interrupted. As after any interrupt, nothing
starts on its own: the next mail, or your next prompt, brings the waiting mail (#13, #14). - Fix: a member that went gone in the middle of a turn (its process exited, its session ended, or
the daemon restarted) was never woken by mail; the mail waited until someone resumed it. Mail now
wakes it as it wakes any gone member (#18). A headless worker whose process ends on its own (a
crash, notagent stop,team downor a daemon shutdown) is also woken at once for the mail it
had not finished, its task included: one automatic restart per mail. - Fix: in opencode, a run that failed before the model answered (for example, a model that does not
resolve) with piggery mail in it was nudged again and again and never ended. It now ends failed:
the mail is not taken as read and comes again with the next mail (#27). - Fix: cleanup (
piggery gc, and the daemon's own) deleted unread mail that a closed team or gone
solo had sent to someone outside it, and once that person had been given such mail, cleanup of
the team or solo failed on every run. Mail sent out now stays with its recipient until it is
read; the team or solo is kept until then (#17). - Fix: the
settlednotice ("nobody is working and no mail waits") left out mail waiting for a
member that had gone and could not be woken (a limit refused it), so it could tell you a team was
done while mail sat unread (#21). - Fix:
cccopies and timer notices sent to a role still went to a member that had left the team,
where nobody reads them (#23).
Teams and sessions:
- Fix:
agent stopandagent resumetreated a session admitted into a team as a headless worker.
A member could stop a session a person runs, and one mail later the daemon ran that conversation
a second time in the background, while the person's own session was refused. Both now refuse a
session, aspiggery killandpiggery resumealready did (#19). - Fix: when a session reopened the team it had been the gate of, the taskforce it had called in the
meantime was closed as orphaned, its workers stopped mid-task. The taskforce now stays with the
session (#22). - Fix: after a Claude Code session's row moved (its gate closed its own team,
piggery team down,
or an in-process resume), its piggery tools stayed bound to the old one: mail no longer woke it,
and tool calls could fail withrun.stale. A gate closing its own team was also told
refused (host.unknown)although the close succeeded (#16). - Fix: Claude Code's session identity. After
/clear, a reconnect of piggery's MCP server (a
daemon restart is enough) put the old session id back, so a wake by mail resumed the conversation
from before/clear(#24)./branchturned the session into a new solo, and its participant went
gone with its mail (#25). A session forked outside its process (Paseo's Rewind) became a new solo
with an empty inbox (#13). - Fix: a manifest with a typo inside a role, a
spawnblock or a routing rule founded a team, the
typo silently became a default, andpiggery checksaid "No problems" (#20). - Fix: a worker whose first start failed before its harness made a session (a model or provider
that did not resolve) could never be brought back:agent resumeasked the harness for a session
that did not exist, although the error said to fix the cause and resume. It now starts a fresh
session under the same id. This was true of every harness but pi. - Fix: a session of yours that mail had woken once, and that went gone again, was woken the next
time into the conversation from before your last/clear. It now always resumes the newest one. - dsh 0.2.0-rc.2 and opencode 1.19.0 are tested. dsh rc.2 no longer reads
~/.dsh/settings.yaml:
a custom provider is a row of$DSH_HOME/cordis.patch.yml(see the reference's dsh notes).
Thanks to @Patruxs for the reports, each with a test that reproduces it.
v0.10.0
piggery runs on Windows (experimental), a team or solo can close its gate to other teams, and lead-peer replaces p2p as the default template.
Before you upgrade:
p2pis no longer built in;lead-peeris the default. A session asked to set up a team
without a template now founds alead-peerteam and becomes its lead,piggery template new
copieslead-peer, and a solo takes its limits from it (the same numbers as before). Teams
already founded fromp2pkeep running: a team keeps the template it started with. The copy in
~/.piggery/templates/p2pis deleted when the daemon starts, unless you edited it: an edited
file stays, with its directory, as your own template.- piggery's own Paseo plugin is gone, and so is
piggery setup paseo. In Paseo, use
PigMonitor, which does more. To remove the old plugin:
paseo plugin remove piggery, then delete~/.piggery/paseo.ps --view,ps --json,
tail --viewand--no-start, which such a plugin reads, are unchanged.
After upgrading, run piggery restart. The daemon updates the integrations it installed: pi to 13,
omp to 13, dsh to 14 and opencode to 10. Then restart the sessions that were open, or run /reload
in pi. Claude Code and Codex need nothing. The database moves to schema 28 at the first start (a
copy of the old one is kept in ~/.piggery/backups/).
Closed gate:
- A team or a solo session can close its gate to other teams. Others no longer see it in
who, and a send to it (by id, by name or as a reply) fails like an unknown name; it sees none
of them and cannot send to them. Unread outside mail is held while the gate is closed, neither
delivered nor acked nor deleted, and arrives when it opens. Nothing changes inside a team, and a
caller and its taskforce always reach each other. gate: open|closedinconfig.yamlsets the gate of a new solo (defaultopen). A solo,
or a team's gate, closes or opens it when you ask withagent action=gate_close/
gate_open. A team it founds or reopens, a taskforce it calls, and a session left solo when its
team closes start with the same state.who,psandtopshow[gate closed];ps --jsonhasgate_closed.
Windows (experimental, amd64 and arm64):
- The daemon, workers and harnesses run natively. The daemon listens on a named pipe that only
your user can open (piggery.pipein~/.piggeryholds its name). Each worker runs in a Job
Object, so a worker, the.cmdshim it was started through and its children end together, and a
daemon that restarts after a crash finds and ends the ones it left. - Install and update. Releases carry
piggery-windows-<arch>.exe.install.ps1installs it
(irm https://raw.githubusercontent.com/sting8k/piggery/main/install.ps1 | iex), andpiggery updateworks there: the binary it replaces, which may be running, is kept beside the new one as
piggery.exe.olduntil the next update. piggery setup claudeandsetup codexwrite hook commands each one runs on Windows. Claude
Code gets piggery's path with forward slashes (it does not run a hook whose path has
backslashes). Codex gets the path's 8.3 short name when the path has a space, since some Codex
versions run no hook command with a quote in it.piggery setup notify add desktopandadd ntfy:<topic>write PowerShell hooks on Windows (a
toast, a push through ntfy.sh) that need nothing installed.herdrhas no Windows script. Your
own hooks innotify.dmay be.exe,.cmd,.bator.ps1; a.shhook is skipped there.- A harness installed with npm or pnpm starts as a worker. Its
.cmdshim is seen through,
and the script runs with the interpreter the shim names (bun for omp), not always node. - A worker's agent directory shares yours without Developer Mode. Where a symlink cannot be
made, pi's and omp's entries become junctions and hard links, not a copy of the whole directory
at each spawn: a worker's sessions and a login it refreshed are your own. - A Claude worker starts whatever the length of its role card. Windows limits a command line
to 32,767 characters, which a card carrying your ownpromptsrules can pass; the card goes to
Claude Code in a file of the run's directory there (--append-system-prompt-file).
Also:
- Built with Go 1.26.9, which fixes GO-2026-6617 in
net/http.
Thanks to @dinhhung893, whose piggery-winport the Windows port learned from; to @KiraKas-Tr, who
tested it on a real Windows machine and found what CI could not; to @haohao3k, whose report and
reproduction (#11) led to the closed gate; and to @Patruxs for PigMonitor.
v0.9.1
A pi session no longer misses mail that arrives just as it finishes a reply.
After upgrading, run piggery restart: the daemon updates the pi integration it installed to 9
(omp to 9 and dsh to 10, which share its adapter file and behave as before). Then restart the pi
sessions that were open, or run /reload in them.
- Fix: mail that reached a pi session at the very end of a reply was shown to the model, and pi
went on working with it, but piggery took the turn as finished. Mail sent after that waited,
unannounced, until pi stopped for good or the model checked its inbox. The turn now stays open
while pi works on that mail, so later mail is steered in as usual and nothing is acked before
the model has read it. - Fix: a stopped worker no longer leaves an empty directory under
~/.piggery/run/. Existing
empty ones go whenpiggery gcremoves their worker.
v0.9.0
A session can call up a taskforce for one job, a team's gate stays with its founder, and lead-peer, dual-lens and advisor join the built-in templates.
Before you upgrade:
supervisor-executoris no longer built in:lead-peerreplaces it (rolesleadand
peer). A copy in~/.piggery/templatesstays as your own template and teams made from it keep
running, but it gets no updates, andpromptsentries inconfig.yamlthat name its roles apply
to it only; add entries forlead-peer/...to give those rules to the new template.slp
changed too: its Supervisor no longer writes to a Peer directly or pins to the board. Anslpyou
never edited is refreshed when the daemon restarts; a running team keeps the template it started
with.- A team's gate no longer passes to a peer while its founder is away. The gate is the member
that founded the team (or reopened it), stored on the team: closing its session, a crash or a
daemon restart leave it the gate. Mail for it waits in its inbox until it is back, a send to the
team from another team is queued instead of refused, and no peer can close the team or take its
cross-team mail meanwhile. The gate moves only when it leaves the team (the next member that
joined takes over,gate_movedinpiggery log) or the team is reopened. A worker is never
the gate. Existing teams get one when the daemon starts: the member that joined first, a session
before a worker. - Mail now wakes a member that is gone. In an open team, new mail for a member whose session
you closed starts that session again as a headless worker, which costs a model run;psshows it
as a worker. The limits ofpiggery resumeapply (max_respawn_per_hour,concurrency,
directories), the gate is never woken, and a worker that stops with the mail unread is woken
again only by newer mail. If you open the session yourself, the worker is stopped (about 2.5
seconds at most, a turn in progress can be cut) and the session is yours again. Before, such mail
waited forpiggery resume. - The database moves from schema 22 to 27 at the first start. piggery copies it to
~/.piggery/backups/pre-v22-27-<date>.dbfirst (the three newest copies are kept). v0.8.0 does
not open a newer database: to go back, stop the daemon, install v0.8.0 and put that copy in
place ofpiggery.db, deletingpiggery.db-walandpiggery.db-shmbeside it. Whatever happened
after the upgrade is lost. - Open sessions keep the old extension until you restart them. The daemon updates the pi, omp,
dsh and opencode extensions at its first start (versions below), sopiggery setupis not needed
for them. Claude Code, Codex and Paseo installs did not change.
In this release:
- Integration versions since v0.8.0: pi 3 to 8, omp 3 to 8, dsh 4 to 9, opencode 1 to 6 (claude 1,
codex 1 and paseo 3 are the same). - A solo session or a team's gate can call up a taskforce:
spawnwith atemplateand a task
builds a temporary team from a template that has ataskforce:block, in the caller's directory
(named after the template unless you give a name), and starts its chair as a headless worker. The
chair sends the result back as mail and stays for follow-ups; only the caller closes the
taskforce, from outside (a close from inside it, the chair's included, is refused). If every
member stays idle fortaskforce.idle_for(20 minutes in the built-ins) you get one notice for
that idle stretch. A taskforce closes with its caller, and also when its chair stops (gone, left or
parked): its other members are stopped as withteam downand the caller gets one notice, "Taskforce X
closed: its chair stopped." A closed taskforce is
never reopened (call its template up again), and a taskforce never calls another. Its caller's
limits.concurrencycounts the taskforces it has open; the taskforce's ownlimits.depthcounts
from its chair.spawn template=also takes acwd, the
taskforce's directory (and its chair's): relative to the caller's or absolute, and inside the
caller's root (a gate's team root, a solo's own directory), a git worktree of that repo, or a
spawn.allowed_rootsentry, else it is refused; nocan_set_cwdis needed, and without it the
taskforce works in the caller's directory. In a shell:
piggery agent spawn --template T [--name N] [--cwd D] <task>andpiggery agent close [<team>]. A key
piggery does not know inside ataskforce:block is ignored, andpiggery checknames it. council,dual-lensandadvisorare taskforce templates. The prompts ofcounciland
dual-lenswork both ways: founded by you as a long-lived team, or called up by a session (they
answer the caller, and only read unless the task says they may edit). The leads oflead-peer
andslpcall a taskforce for a one-off second opinion instead of spawning a Peer. The card of a
solo and of a gate lists the taskforces it can call and says when to call one: a second opinion, a
review that matters, a decision or approach it is stuck on, or a short bounded job, not work it can
do itself; each taskforce's summary says what it does and whether it edits.- The
agenttool of pi, omp, dsh, opencode, Claude Code and Codex takestemplateonspawnand
teamonclose. piggery template listhas ataskforcecolumn that marks the templates a session can call up.
psandtoplist a taskforce right under its caller, a step in, with ataskforcelabel in
place ofteamand the caller's name (caller=inps,for <name>intop);ps --jsonhas
parentandparent_idon such a team andunderon its unit inprojects, andps --viewhasunderanddepthon its block and
taskforceandcalleron its head. A closed taskforce is not in the main list or under its caller
any more; it stays in the Closed tab until gc.top's tabs are projects (directories), not teams: All, then one tab per project, then Closed.
Projects with someone alive come before all-gone ones. A tab is named by its directory's last
name, with parent names added until two that clash differ (a/api,b/api), and a bar too wide
for the window slides, with‹ +Nand+N ›for the tabs left out. A taskforce has no tab of its
own; it sits under its caller. All lists only what is alive: no team whose members are all gone, no
gone solo and no closed team (the one-hour grace for a closed team is gone; closed teams are in
Closed). A team with some members alive keeps its foldedN members ✗ gonerow.ps,ps --json
andps --vieware unchanged.- The built-in
lead-peertemplate: the Lead owns the plan, talks to you directly, and judges each
result. A Peer may know as much as the Lead: it follows the brief by default and speaks up only
with evidence that the plan is off, and the Lead weighs that evidence, not who said it. Both
prompts are much shorter. - The
slpprompts are much shorter, with the same Lead and Peer rules. The Supervisor writes to
a Lead as you would, passing on your own words where they carry the request; it talks only to
Leads and watches a lane through its Lead's log. In both templates a Lead writes to its Peers as
a person would, and a Peer's prompt speaks only of its work and the one who gives it. - New template
dual-lens, written as a taskforce: its chair takes one hard technical question or
review, sends the same neutral brief to two lenses, accepts where they overlap, hands each lens
the other's argument where they conflict, decides, and sends the answer to whoever asked. It only
reads unless the task says it may edit. Setlens-aandlens-bto two different model
families; left atinherit, both run the same model. - New template
advisor, a taskforce of one: it gives read-only advice on one hard decision or a
stalled approach (a recommendation, the evidence, the strongest downside, and a check that would
prove it wrong), answers by mail, and stays for follow-ups until you close it. Call it with
spawn template=advisor. - piggery now ships a shared prompt,
~/.piggery/rules/general-policy.md(own the outcome,
question a mechanism before patching it, keep tests and docs minimal), for every role of
lead-peerandslp.setupor the daemon's start writes the
file and adds its entry topromptsinconfig.yamlonce, keeping your entries. Remove the
entry or the file and it stays removed; a file you edited is never overwritten. topandpsshow the template a team was founded from in brackets after its name
(piggery [lead-peer]; not when it is the team's name);ps --jsonhas it asteams[].template.
Members are listed in the order they joined the team (ps,who,gc).- A mail an agent is given again, because it was not acked, says
redelivered="true"in its
header, whatever its age. - When a team closes (
team down, or the gate closes it), a session that was a member goes on as a
solo under the name it had, not a new random one. Only if a live solo or an open team already
has that name does it becomename-2. piggery template listlists the templates a team can be founded from, with their summaries.
team upis no longer in--helpor the public docs (it makes a team nobody can join): found a
team from a session. It still runs, names its team after the directory, and an unknown template
name says which ones exist.piggery --helpfits an 80-column window, one line a row (the full usage of each command is in
its own--help).doctorprints findings before warnings and "no findings" only when there are
neither,logleaves out emptyparticipant=,run=andref=,topandpsdo not repeat a
template that is the team's name, and an empty team intopsays it can be closed. The install
script's last line points topiggery setupfor the full list of harnesses.setupanddoctor...
v0.8.0
opencode joins the farm, and two new team templates come built in: amp-like and gastown-like.
After upgrading, run piggery restart: the daemon then knows opencode and refreshes the built-in
templates you never edited. No existing integration changed, so setup --outdated has nothing to
do. To use opencode, run piggery setup opencode.
- opencode 1.x (tested with 1.18.34): an opencode session you open joins piggery through a plugin,
and a team can start opencode workers (opencode serve, one per worker). Mail wakes an idle
session and reaches a busy one at its next step;abort,stop,resumeandmodelwork on
its workers.setup opencodeadds onepluginentry to youropencode.jsonand refuses an
opencode.jsonc(it prints the line to add by hand). Workers keep your opencode setup, except
thequestionandtasktools (disabled_toolsinharness/opencode.json; a role gets one
back withspawn.allow_tools). - Template
amp-like, after Amp's oracle and code review: a lead does the
work and calls an oracle (hard reasoning) or a reviewer (one diff), each answering once. It pays
off when they run another model family than the lead. - Template
gastown-like, after Gas Town: a mayor splits
the work, polecats do each task on their own branch and worktree, and a refinery merges the
branches one at a time into an integration branch. Your own branch moves only when you say. council: the chair stops at the verdict and starts agents for other work, such as carrying out
the decision, only when you ask.- manifests/README.md draws every built-in template, with when to pick it.
- Forks get an
AGENTS.mdwith the rules that keep the design intact, for people and coding agents. setup <harness>keeps one copy of each of your config files it is about to change for the first
time, in~/.piggery/backups/setup/<harness>/.setup removestill takes out only piggery's part
and never restores the copy; it is there if something goes wrong.- Fix:
setup pi --extthensetup remove pileft asettings.jsonof{}where there was none,
and could re-indent other values in it (such aspackages).
v0.7.1
Codex threads that share one app-server are no longer mixed up.
After upgrading, run piggery restart, then restart Codex (the Desktop app, or the shared
codex app-server and its TUIs). No integration changed, so setup --outdated has nothing to do.
- Fix: Codex Desktop, and TUIs started with
--remote, run every thread in onecodex app-server,
and piggery made all of them one participant, so mail or a wake could reach the wrong thread or
project. Each thread is now its own participant; a piggery tool call there that does not say
which thread it is from is refused. A Codex TUI and Claude still keep one participant across
/clear. Participants already mixed up stay so until they are closed. Reported by @haohao3k
(#4). - Fix:
--adminon an agent's command (such aswho) now points topiggery psinstead of the
removeddump, andgc's usage says--closed-before DURATION(such as168h).
v0.7.0
piggery now tells you, by itself, when a team's mail flow needs you, and piggery check tests your
files before a restart.
After upgrading, run piggery setup --outdated: the pi and omp integrations are now 3 and dsh 4
(Paseo, Claude and Codex are unchanged). Then restart the pi, omp and dsh sessions that were open.
Breaking: only piggery writes to notify now. An agent's send to notify is refused, and a
to: notify routing line or a notify: notify timer in a template is ignored with a warning
(piggery check lists them). Notify hooks run from ~/.piggery/hooks/notify.d/; a single
~/.piggery/hooks/notify is no longer run, so move it into that directory.
- Notices, decided by the engine at the end of a gate's turn, from the team's mail alone:
reply
(a turn on team mail ended and the gate sent nothing),settled(the gate sent its last message
and nobody works or has mail waiting),failed(a turn on team mail failed, so that mail waits)
andgate_lost. Your chat with the gate, a gate that is still dispatching work, a headless gate
and a member that is not the gate never notify. The hook's JSON line addsgateanddir,
andkindis the notice's kind. The respawn-limit notice goes to the worker's lead only. piggery setup notify add desktop|herdr|ntfy:<topic>writes a ready hook intonotify.d/
(removetakes it out; alone, it lists the hooks and what each needs). Every file there runs in
parallel, each with its own 10-second limit.piggery check: readsconfig.yaml, the harness profiles, every template and your prompts with
the daemon's own loaders and prints what they would refuse or ignore; it changes nothing.- The daemon checks once a day for a newer release;
top,setupandupdate --checksayvX available: piggery update. Nothing is installed on its own;update.check: falseturns it off. topshows the latest notices at the bottom left, beside the events;nopens or closes them,
likeefor the events.ps --viewcarries them asnotices, and the update notice as
daemon.update.- The template list an agent reads now also shows a template that
team upwould refuse. - Fix: a build stamped
dev-<sha>is treated as a build from source:piggery updateno longer
replaces it with an older release unless--force.