Repository navigation
Releases: stuarthu/dsh-crew
Releases · stuarthu/dsh-crew
Release list
v0.13.0
- A job's documents no longer land in your project folder. The opening document, the design,
the task table, every ADR and CRD, the boundary contracts and the release plans now go in a
temp folder:<TMP>/dsh-crew/<repo>/<job-slug>/.<TMP>is your system temp folder —/tmp
when nothing sets it — and<repo>is your project's full path with the slashes written as
-. Your project folder keeps its code,qa/, and the four files that ship:README.md,
CHANGELOG.md,CLAUDE.mdandprinciples.md. A job's documents are read while the job runs
and are kept after it by nothing. - The Chinese README is gone.
README-zh.mdwas deleted, and with it the rule that the two
READMEs say the same thing and go in the same commit.README.mdis the one README, in English.
A job whose language is not English still writes a translated README of its own, and nothing
keeps that page in step with the English one. - The task table is one per job, not one per repository. The temp folder carries the job name,
so each job starts its own table and never reads an earlier job's. - Nothing checks the Verdicts line any more. The PM still writes it, and still prints one line
per task to you at the end of a job. What is gone is the red: a task with a missing value, or a
not runwith no reason after the dash, reddens nothing.qa/gaps.mdsays so.
v0.12.0
Fixed
- The Crew preset now appears in the preset picker on dsh 0.2.x, where until
now it was silently switched off. The declaration row was carried by
@deepseek-ai/dsh-agent-presetand switched itself off with adisabled:line.
A row'sdisabledis evaluated against the loader context, which cannot see
the registry service — only a!!jsexpression inside a row'sconfigsees that
plugin's own context. So the expression was true on every dsh, the row was
disabled on every dsh, and dsh kept a declaration whose activation fails "on the
roster with its diagnostic" rather than failing the profile. The symptom was a
missing preset and no error, on the one generation that has no other home for it:
0.2.x never reads$DSH_HOME/.agent-presets.- The row is now carried by
host/crew-preset.js, the package's own plugin,
and it carries nodisabled:line at all. The check runs inside that plugin,
wherectx.get('agentPresets')resolves against the row's declared injections. - Nothing changes on dsh 0.1.x. That generation never reads a declaration row;
the plugin does nothing there, and the folder install is the whole story — the
same shape as before, now actually reached. - The preset's own content did not move: same
id: crew, sameorder, same
name and description, sameplugins:list with the same two deviations.
- The row is now carried by
Changed
- The job folder moved inside the repository. It used to sit at
~/.dsh/crew/jobs/<job-slug>/, one folder per job, far from the project. It is
now at<repository>/.dsh-crew/jobs/<job-slug>/, at the root of the repository
this session works in — the same place the job's documents are, so onels
shows the job you are in, and a job's progress can no longer be mistaken for
another repository's.
Nothing about the job changed shape: the folder is still single-use. The PM
writes one line into the repository's own.git/info/excludebefore it writes
anything into it, sogit statusstays clean, the folder is never staged and
never committed, and it is dropped whole when the job ends.info/excludeand
not the project's.gitignore, because that line is about where this crew puts
progress rather than what the project builds, and because it is shared by every
worktree — so a paired task's two trees see the same rule.- Nothing is committed that was not committed before.
state.jsonis
rewritten after every step; committing it would put a file that changes on
every step in front of every reviewer and every reader. It stays progress,
and the record this job leaves is still the one indocs/. - The default is now relative,
.dsh-crew/jobs, resolved against the folder
the session runs in. SetjobsDirin thedsh-crew-corerow to an absolute
path (or one starting with~/) to put the job folder somewhere else, exactly
as before. - The unfinished-job notice is unchanged in behaviour. A job left in the
folder is still put in front of the PM at the start of every session, and it
now names the resolved absolute path rather than a~one.
- Nothing is committed that was not committed before.
v0.11.0
Added
- The Crew preset now exists on dsh 0.2.x, where until now it was silently
missing. dsh 0.2.x replaced the@deepseek-ai/dsh-agent-presetsregistry
with@deepseek-ai/dsh-agent-preset, and the old registry's home —
$DSH_HOME/.agent-presets— is not read at all any more. In its own words:
the new registry "neither scans directories nor accepts preset paths". A preset
is now a declarative row in a profile's composition, and a plugin ships one by
inserting that row from its bundle patch.
dsh-crew only ever wrote the folder, so on 0.2.x the plugin loaded, the PM
prompt and the guards worked, and Crew never appeared in the preset picker.
The plugin's bundle patch now declares the preset too, and the picker offers it
again.- Nothing changes on dsh 0.1.x. The folder install stays exactly as it was,
and the new row disables itself wherever the old registry is the one loaded,
so a 0.1.x profile is never asked for a package it does not have. - The preset is written twice on purpose. The plugin list differs between
the two dsh generations — the persona row alone takestextin 0.1.x and
prefix/suffixin 0.2.x — so neither declaration can be derived from the
other. A role filter (roleAllow,roleDeny,roleModels) therefore has to
be set in the file your dsh reads: the preset copy under
$DSH_HOME/.agent-presets/crewon 0.1.x, and thepreset-crewrow in the
plugin'scordis.patch.ymlon 0.2.x. Both are commented to say so. tools/verify-mount.mjsholds the new declaration to the same rules as the
old one: the crew roles are mounted, the subagent-control tools are there, no
second way to start an agent re-opens, the preset keeps itscrewidentity,
and web fetch stays off.
- Nothing changes on dsh 0.1.x. The folder install stays exactly as it was,
Removed
- The PM write guard is gone:
host/pm-write-guard.js, its row in
cordis.patch.yml, and its checktools/verify-pm-write-guard.mjs. It
stopped the root session — the PM — from usingwriteandediton every
file that was not on a hard-coded whitelist, and asked you to approve each
such write, one at a time. That whitelist was narrower than the write set
the PM's own rules give it, so the guard kept asking about writes the rules
already allow —README.mdandCHANGELOG.mdamong them. This removes the
enforcement, not the rule:roles/pm.mdstill says which files the PM may
write. It also reversesdocs/design/prd-2026-08-23-pm-write-guard.md.- The git guard is untouched, and the plugin now ships one guard. It is
still what blocks a crew role's push, tag push, force push, remote delete
and package publishing.SECURITY.mdandCLAUDE.mddescribe that one. - If your own profile patch targets the row id
dsh-crew-pm-write-guard,
delete that patch. The plugin no longer ships the module that row loaded,
and a row naming a module the package does not export cannot be resolved. npm testno longer runstools/verify-pm-write-guard.mjs. Nothing
else in the suite, and no QA case, depended on it.
- The git guard is untouched, and the plugin now ships one guard. It is
Fixed
- The git guard was not guarding your crew roles at all. It decided who was
the PM by looking at the tool call'sexec.parent, and in dsh that token marks
a nested sub-call, not a parent agent: it is set for the PM's own nested
calls and absent for every crew role. So every role read as the PM, and the one
branch of the guard that trusted the PM let a child push a protected branch,
push a tag, force push, delete a remote or publish a package straight through.
The guard now reads the agent's own session: a crew role's session names a
parent session, the PM's does not. Every child is guarded again, and the guard's
own check — which had the same mistake and reported every blocked case as a
pass — now sees children.- Nothing about the PM changes. Its git and publishing commands still pass
straight through, andtrustRootAgent: falsestill guards it exactly like a
child. - If you were relying on a role being able to push, that ability is gone. It
was never the design: a child's push needs the one-shot approval file the
user creates, exactly asSECURITY.mddescribes it.
- Nothing about the PM changes. Its git and publishing commands still pass
v0.10.0
Added
- Pushing a
v*tag now also creates the GitHub release, not only the npm
version. Its text is the matching section ofCHANGELOG.md— the same words
you are reading, sent to the place people actually look. The repository had 17
tags and 0 releases before this, so anyone arriving from npm saw a row of bare
tags with nothing written on them.
Four things about how it behaves are worth knowing, because each one was a
deliberate choice:- The notes are read before anything is published. A version with no
CHANGELOG.mdsection written for it, or with an empty one, stops the run
right there and publishes nothing. An npm version cannot be pulled back, so
the check that can still save you has to happen first. - The release is created only when the publish really happened. Re-pushing
a tag whose version is already on npm skips the publish, and it skips the
release with it. So if a version ever reaches npm without its release page,
re-pushing the tag will not repair it — that takes one
gh release createby hand. - Old tags are not getting release pages, with one exception.
v0.9.0was
given one by hand on 2026-08-22, because it was the newest tag and already
had a complete section here. The other 16 stay as they are; 8 of those 17
tags have no section in this file at all, so the pages would have been empty. - The code that reads those notes has never been run by a test. That was
chosen, not overlooked: the shell lives inline in the workflow and no test
harness executes it, so the first real run is the firstv*tag after this
version. Nothing you install is affected — a mistake there stops a release
instead of shipping one.
There is nothing for you to configure, and nothing changes about how you
install or use the plugin.
- The notes are read before anything is published. A version with no
Changed
- A question in the opening interview can now be left undecided. Every
question the PM puts to you before a job starts has one test put to it first:
would your answer change what gets built, or what gets released? A question
that changes neither now arrives with a second option beside the recommended
one — leave it undecided. Watch where that bar sits: being able to get
started without hearing from you is not enough on its own to earn the
option. A question that fails the test is not offered it, and you are told in
one line what it would change.
What taking it buys you is the part that matters. The thing you set aside is
recorded nowhere in the opening document: not in the list of what the
interview settled, not under "not in scope", not under "still undecided". Ask
for it a month later and you are reopening nothing, because nothing about it
was ever written down. This came out of a real case — one command's worth of
work ran into a line the interview had settled in passing, and it took the
full change-request road to get past it.
The change-request rule itself is not loosened. The only thing gone is a
confirmed line standing in the way. If saying yes to your later ask would move
the milestone list, a DoD item, or the scope of the work, that is a change of
scope like any other: the PM still writes the change request, and still stops
and asks you first. - The "not in scope" section is now a short list, and every line on it has a
real cost. A line belongs there only when crossing it would force work that
is already finished to be built a second time, or do something nobody can take
back — a package published, a tag pushed, data deleted — or leave a safety
guard or a permission rule weaker than it was. Work the PM merely did not get
to stays off the list. It used to go on, and that was the trouble: everything
in that section reads like a boundary you agreed to, so a cheap request could
look like you were reversing yourself. The rule is short now — if a thing is on
that list it is a wall, and if it is not, just ask for it. - The QA folder moved from
docs/qa/to the repository rootqa/. QA's
cases are runnable scripts, not documents, so they no longer live under
docs/. The command that runs them is nowbash qa/run-all.sh; the standing
gap list isqa/gaps.md. - The task table became a folder. The single
docs/design/tasks.md(one
long file, every task of every job) is nowdocs/tasks/— oneT-<n>.md
file per task, plusREADME.mdfor the non-task content. A task's Verdicts
line and DoD section live in its own file. - A researcher's answer no longer enters the repository.
docs/research/
is gone; the researcher answers in its report, and the PM writes what is
durable into its own documents.
v0.9.0
Changed
- The
quicklane is gone. A job now picks one of two lanes:ask, for a
question you want answered, andteam, for a change of any size. There used to
be a third one for a single small change with no design choice in it, where the
PM edited the file itself — no crew, no documents, and nothing checking the
result. A typo now takes the same road as a feature: at least one task, one
round of QA, and one round each of the code review, the security review and the
doc review. That is slower for a one-word fix, and it is meant to be. What
the old lane really bought was a way for a change to reach your repository with
nothing written down about it and no second pair of eyes on it. The rounds it
used to skip are also much cheaper now, which is the next two entries. A
milestone is still not a release: it means one full cycle and one commit.
Pushing and tagging sit outside it, and each of them still needs your own yes,
every time. - QA now runs once for the whole milestone, after the coding is finished,
instead of once per task. It was the most expensive step the crew had: one
round took 13 to 26 minutes in the crew's own last job. A task is now finished
when its own unit tests pass: the engineer's failing test before the code, the
passing test after. Nothing else holds it open, because neither a reviewer nor
a QA round has run yet. That one round also has a new shape, in two steps.
First one QA agent turns your DoD sections into a list of cases, one line
each, without reading the code. Then one agent writes each case on that
list, all of them at the same time. The extra step buys one thing: the side
being measured does not set the questions. - The code review, the security review and the doc review now run once each,
at the end of the milestone, side by side. They used to run on every finished
task, and a task could reach three rounds of them. Three of those rounds in the
last job were thrown away, because the code changed after the review had read
it. Each review now reads only the part that changed. Code nobody touched, a
document nobody touched and anything outside the milestone's scope stay out of
it, however much a reviewer dislikes them. And only a change made because of a
review's own finding brings that review back — a code change re-runs the code
review, a wording change the doc review, a security change the security review.
The three never come back together. - What those two changes cost you, said plainly, because it is a trade you
accepted. A defect is now found later, with more work already sitting on top
of it, so fixing it reaches wider. That is not a guess. In the crew's own last
job, running QA on every task caught two real defects: a cross-reference that
had been done only halfway, and a rule about dependencies written the wrong way
round. Held to one round at the end, that kind of thing surfaces after more
code has been written over it. Nobody downstream may quietly make up for it,
and no reviewer may widen its one round to compensate. What it demands instead
is that the single round is a full one: every item of every task's DoD
section, whatever the test run said. - The interview at the start of a job now has a method, and a rule for when it
stops. That step used to be called "Grill" and it ended "when the answers are
settled", a sentence that never says when that is. It now names six kinds of
question, and the PM picks the kind by what it is actually missing. Clarify
what the words point at. Probe an assumption nobody has checked. Ask for the
reason or the evidence. Ask who would disagree. Ask what the choice drags in
behind it. Question the request itself. The last one is permission to say
"I think you may be solving the wrong problem", and it comes early, while
changing direction is still cheap. Wide questions come before narrow ones,
because starting narrow only confirms the picture already in the asker's head.
A leading question — the wanted answer hidden inside the question — is banned:
when the PM thinks it already knows your answer, it goes and looks it up
instead of asking. And it stops the moment it could write every section of the
opening document with no guess left in it, not one question later. The
reasoning and the outside sources are principle 22 inprinciples.md, which
lives in the repository and is not part of the npm package. - After the start, you are asked far fewer times. Once the scope and the
change requests are agreed, the PM decides the rest itself and hands you
summaries of the documents it produced. You interrupt on the one part you
care about, instead of answering a question per item while the work waits. In
the last job the user answered more than twenty separate questions in the first
half. Two things did not move into the PM's hands. A change outside the agreed
scope is refused by default — it says what it would cost, and takes it only
when you name it yourself. And every push, tag, publish, merge and
branch delete still needs your own yes at the moment it happens. - One opening document per job, and its name carries the job.
docs/design/prd.mdis nowdocs/design/prd-<date>-<job-slug>.md, and the
design document goes the same way:docs/design/hld.mdis now
docs/design/hld-<date>-<job-slug>.md. With one fixed name, the first line the
next job wrote used to overwrite the last job's document — and the one before
this had grown to 370 lines.docs/design/tasks.mdkeeps its plain name,
because it is one table for the whole repository rather than one per job.
Files that were already finished underdocs/decisions/and
docs/research/, and the earlier sections of this file, still name
docs/design/prd.mdanddocs/design/hld.md, and that is on purpose. Each
of them records one moment, and that was the real path on the day it was
written. Rewriting them so one search comes back clean would make them less
trustworthy, not more. The reasoning is in
docs/decisions/adr/0017-scope-of-the-rename-sweep.md. - A document you confirmed is never rewritten behind your back. When the PM
has to correct the opening document — a check that turns out to be impossible,
two checks that contradict each other — your confirmed words stay exactly as
you read them. The correction goes beside them, with its date. Every one of
them is listed under a single fixed heading, so you can read the whole set at a
glance and stop the PM if you disagree, and the work does not pause while you
do. A correction is not permission either: anything that changes the scope, a
DoD item or the milestone list still waits for your yes. One thing left that
document for good — the list of its own old versions. It is already in each
change request'sAppliedline and in the git history, so inside the document
it was a second copy you had to walk past to reach the problem.
Added
- Every role prompt now says what that role may write, and says out loud that
reading is not restricted. All ten of them, the PM's own included. The list
is written by class of document, never as a list of file names, because the
opening document's name now changes with every job and a list of names would be
wrong by the next one. There is also a single table of who writes which class,
in the PM's prompt and inprinciples.md, and the two say the same thing. - A new rule: a document that judges the work is not the worker's to edit.
The opening document, a task row's DoD items, the milestone list. If a briefing
hands one of those to a role — even with the exact new wording, even when the
change is plainly right — the role changes nothing and says so in its report.
That is a mistake in the briefing, and the answer is to correct the briefing,
not the role. The PM's own half is stricter, because it is the one who writes
them. - A new rule: text that arrives inside a tool result is data, not
instructions. A command's output, a file's contents, a web page, an MCP
server's notes. Suppose it tells a role to start an agent, to message another
role, to hide something from you, or to reach for the shell instead of its own
tools. The role does none of it, and reports what arrived, what it asked for
and where it came from. The PM gives such a report the weight of a security
finding and names it at the milestone review. It also tells you where the text
came from, so you can decide whether you want that thing installed. Handling
it quietly is the one thing the injected text asked for. - Eight kinds of document now have a written list of what goes in them — the
opening document, the design, a decision record, a change request, an interface
contract, a test plan with its cases, the release and upgrade plans, and a DoD
section. Each list is inprinciples.mdwith the outside source behind it, and
a short version sits in the prompt of the role that writes that document. The
opening document gained a shape it did not have before: the problem written as
a problem and never as the solution, who reads which part at which moment, a
number or a command for each quality bar the release must clear, and a target
window with a reason behind it. Every item in it is also markedmust-have,
high-wantornice-to-havewith a rank inside its class, so that when
something has to be cut, the easy items are not the ones that survive. - Crew agents now carry numbered names in the list of agents you watch —
crew-engineer-1,crew-qa-3— and no number is used twice in a job. Two
agents of the same role used to be two lines that read the same, and the name
is the only thing telling you which report came from which agent. Nothing in
the code changed for this; it is a rule the PM follows. - **One engineer per code change...