Repository navigation
qargi 0.2.0
Added
-
qargi marshal forget NAME: drops this machine's accepted marshal mark of one feature, so a stale mark (left after the feature was
deleted or re-created on the remote) stops reportingrollback detected. It needs integrity advisory or strict and a mark for NAME,
prints the mark's revision and commit in a plan whose token covers both, applies with--planand your words (audited as
marshal:forget), touches no other feature and nothing on the remote, and is refused in a member run. -
qargi project adopt PROJECT: closes the safe gaps of an attached repository. With a plan token and your words it creates the missing
long-lived branches locally (at the default branch tip; none is moved) and writes the methodology files that do not exist as one commit
onagent/adopt-<methodology>cut from develop, for you to review. It never overwrites a file, never pushes, leaves the working tree
alone, refuses a dirty tree, a detached HEAD and a member run, and lists the changelog format, tag format and CI content as left for you. -
Signed marshal records. With the shared marshal, each lead machine can have its own ssh key (
marshal key init), a per-project
signers file lists the trusted keys (marshal signers add|remove|list, never in the repository or the refs), and
marshal enable --integrity off|advisory|strictsets the mode. Records are signed withssh-keygen -Y(namespaceqargi-marshal) over
a canonical payload that names project, feature, kind, revision, parent and lead, so a record cannot be altered or moved to another
feature. Advisory tags records signed, unsigned or INVALID; strict ignores unsigned and invalid ones and falls back to the last
accepted record. A local high-water mark detects a rewound ref (rollback detected), and junk or replayed pushes neither renew a lease
nor block a feature.marshal resign NAMEsigns an existing record when moving from advisory to strict. Keys, signers and the mode
are yours to set; nothing is signed until you choose a mode. Members cannot read the signing key or change the signers.
Review hardening: a lagging machine builds on the newest signed record rather than overwriting it; advisory builds on an unsigned head
instead of dropping it; a signed finish records the last features commit so a reused name keeps its rollback mark; records are
identified by what the signature covers, so a re-committed head is the same record;resignshows the head, lead and goal in a plan
whose token covers that head and refuses a lead other than the accepted one;disableneeds the plan token and your words while
integrity is on; the guard followspushd/popd, refuses links and moves of the key, and normalises/./in scanned text.
Member definitions now also hook the guard on the Read and Grep tools (to keep the key unread); members created earlier keep the old
matcher until they are refreshed (qargi agent refresh NAME). -
Shared marshal.
qargi marshal enable|disableswitch a project between the local records and a shared backend that keeps each
feature record as a commit onrefs/qargi/features/NAMEof the remote origin: create-only claims, leased updates, an atomic move
torefs/qargi/done/NAMEon finish, a fetch that never brings other refs, and takeover judged on the taker's own monotonic clock.
It is off by default, needs the plan token and your typed words, is audited, cannot be used from a member run, andproject set
refusesmarshal.*exceptmarshal.ttl. Offline verbs use the cache and sayremote not checked; an offline claim is
provisional.local verifyignoresrefs/qargi/;marshal status|checktake--no-fetch(the session hook uses it).
Hardening from review: an offline claim is dropped, not pushed, when another machine finished the feature meanwhile; remote records with
wrong field types are ignored instead of crashing readers;takeoverof a provisional claim is refused; the lease renewer survives an
unreachable remote (exit status 3,remote not checked) and stops only on a lost lease; the fetch leavesFETCH_HEADalone (git 2.29+);
marshalignoresAPPROVEDandPLAN_ARGfrom the environment; andqargi feature start|finish|verifyare refused to a member. -
Cloud profiles. A project can provision two cloud base agents,
<project>-worker(write class) and<project>-reviewer(read-only),
and start a session of a role and profile on one:qargi start|send <project>-worker --role build --profile build. The model and
effort are overridden per session with a full model object and the role's prompt is rendered fresh, so the base needs no prompt
refresh; its tools stay fixed on the agent.agent for ROLE --surface cloudresolves the instance and uses a base only when it is
registered and the provider's cloud override capabilities are verified (they now are forclaude, from a scratch run on
2026-11-01); otherwise the four role agents keep serving, and a profile with a different model than the role agent refuses.
A reviewer base needs the project'sprovider acceptfor the missing cloud read-only barrier before it is provisioned or started.
The claude adapter gained astart-sessionrequest builder, with a conformance check that a body never carries tools, skills or
MCP servers. -
Providers. Each model provider is a descriptor (
lib/providers/NAME.json, one schema) with its tier-to-model map and verification
dates, effort levels, surfaces and a per-surface capability matrix;qargi provider list|show|checkprints and validates them,
andchecksays what degrades (an unverified capability counts as unsupported). Theclaudeprovider has a local adapter
(lib/providers/claude/adapter: resolve, dispatch-local, barrier-check) behind which members are rendered, and the Claude model ids
and id pattern that were spread through the code now come from its descriptor. A surface with no read-only barrier cannot serve
the review role unless the project recordsmodels.accept_no_barrierwithqargi provider accept(plan and token, audit-logged);
forclaudethat means a cloud review role needs your acceptance, while the local guard counts as a partial barrier. A provider with
no effort control has the effort dropped andagent modelssays so,agent forrefuses a profile on a provider that cannot override
the model per dispatch, andlocal verifyandreview applynever apply patches from a read-only run.bash tests/conformance.sh NAME
runs a conformance suite (verb shapes, unsupported verbs, secrets out of argv, a barrier corpus, the read-only definition) against an
adapter, with a deliberately broken adapter proving the suite catches faults. A member cannot runprovider accept. -
Base members and profiles. Two base members, one per guard class:
worker(build, write, test) andreviewer(review, read-only);
qargi agent add worker|reviewerdefaults to the base's own abilities and refuses abilities of the other class. Specializations
are profiles {base, tier, effort, purpose}, resolved at dispatch: shippedbuild,write,test,review,auditor(Haiku),
advisor(Opus) and the opt-inresearcher(frontier tier), plus your own underprofiles.NAMEin a project's answers (validated;
a profile whose abilities do not fit its base's class is refused).qargi agent for ROLE [--profile NAME] [--json]now prints one
line,MEMBER MODEL EFFORT PROFILE, and the lead passes the model and the effort to the Agent tool, which override the member
definition.qargi local prepare --profile NAMEresolves the profile before any clone, records it inRUN/profile(a file the guard
keeps from the member) and printsPROFILE,MEMBER,MODELandEFFORT. The tier-to-model table lives in the provider file
(lib/providers/claude.json, with an alias per tier for local dispatch).qargi agent modelsflags legacy per-ability members,
a missing base, refused profiles and mixed-class members. The earlier model-table entry is superseded:rolesandsuggested
becameprofiles, andauditor,advisorandresearcherare profiles, not members. -
Model selection. One table (
lib/model-defaults.json) names a tier and an effort for the lead and each role (Sonnet 5.5 for the
lead, build, write and test, Opus 5.5 for review), andlib/providers/claude.jsonmaps the tiers (fast, balanced, deep,
frontier) to models; a project chooses the provider withmodels.provider.qargi agent addtakes its model and effort from
the project's answers, else the table, and writes the effort into the member definition (so doesagent refresh); the project
template does the same, and its write role is now Sonnet rather than Opus.qargi agent models [--project P] [--json]shows
the table, the project's overrides, the shipped profiles (auditoron Haiku,advisoron Opus,researcheron the opt-in
frontier tier, Fable 5.1) and each member, marking an alias as unpinned and a frontier member as opt-in. The flow skill has an
advisor sign-off beforefeature finishand says search is a read-only exploration on a small model, not a role. -
qargi marshal status --all(and--brief,--json, and the session-start hook that uses them) lists only the open features;
--historyadds the finished and abandoned records after them.qargi marshal check NAMEfor a name that has no branch and no
record now exits 1 withno feature NAME, and so do the flow verbs andlocal prepare --base feature/NAMEfor such a name.
The error for a branch that is checked out elsewhere says how to free it (git -C DIR checkout --detach). -
Memory tiers (writing, second slice). The session-start hook now lists the notes of the tiers, highest first, as data after the
marshal block (at most 4000 characters per note and 16000 in all; a tier that is missing or unreadable is skipped and named).
qargi memory init TIERcreates a tier from the standard layout andqargi memory move PATH --from TIER --to TIERmoves a
note, or a folder of notes, between tiers; both print a plan and a token and apply only with your approval, and nothing is
synced or deleted without it. A repo tier with notes that are not committed warns with the count.local prepareprints a
TASK-BLOCK MEMORY packet for the member, and the guard refuses a member every verb and script that writes a tier. The memory,
task and canon documents describe the tiers. -
Baseline packs. qargi ships three packs under
packs/:shellcheck-gate(lint every shell file you touch and quote the verdict),
keep-a-changelog(one Unreleased entry per user-visible change, in the same commit) andgitflow-member(a member's part of
a git-flow project).qargi packs seedstores them in your library: it prints one line per pack (add, update, current or
kept) and a plan token, and applies with your approval; an untouched shipped copy is updated when qargi ships newer text, a
copy you edited and sealed or a pack of your own with the same name is kept and never overwritten, and seeding never links a
pack.install.sh(and soqargi upgrade) adds the packs your library lacks withpacks seed --install, which needs no token
and never updates. Link a pack to a project withqargi skill link; proposing links when a project is created or attached is
not built yet. A member cannot runpacks seed. -
Memory tiers (read-only, first slice). A project's memory is five ranked tiers, highest first: repo, cloud, project, shared,
system. A tier is a memory store of the standard layout in a directory (defaults under the qargi root;memory.tiersin the
project answers moves any of them) or, for cloud, the project's memory store.qargi memory tiers [--json]lists them with
their state and note counts;qargi memory checkruns the canon check on each tier that exists and fails when a note path
is present in two tiers (README, INDEX and the like repeat per tier by design). The reference store is not a tier. Nothing is
written to a tier; creating and moving notes between tiers, and the session hook composing them, come later. -
Agents write verified facts only under their own role folder of the memory store;
shared/is curated and reached by
promotion (qargi canon promote --approved) or by the person, and an agent proposes a shared note in its report. The cloud
preamble, the store README, the lead contract, the build role and skill and the canon say so.canon auditstill reports
only cross-role writes, so an agent writing undershared/is not yet detected. The cloud prompts change: refresh them. -
A lead-only ref journal (
ref-journal.jsonlin the state directory) records every local branch that qargi's own verbs create,
move or delete (feature start|merge|sync|finish,release,review apply|prune).local verifynow accepts a branch
change since the run was prepared when the journal leads from the snapshot to the branch's current value, so several runs
prepared in parallel all verify after the lead merged the first one. Remote refs, tags and any unjournaled move are still
refused, and the refusal says so. The guard keeps members from writing the journal; it is trusted only as far as the state
directory is (signed records come later).local preparerecordsRUN/started. -
qargi marshalkeeps one record per open feature: its lead (a Claude Code session, identified by the session id the SessionStart
hook exports asQARGI_LEAD, or--as), a lease, status, goal, plan and note.claim,status [--all] [--brief|--json],
set,check,renew,release --note,take,takeover --approvedandfinish. Tasks, agent branches, worktrees and
files that two features both change are derived from git and the local runs, not declared. Query it before starting work:
qargi marshal check NAMErefuses when another live lead holds the feature and warns about a stale lead, an anonymous
identity and overlap. The lease ismarshal.ttlminutes per project (default 15;qargi project set PROJECT marshal.ttl N),
renewed by the lead's actions and for the whole run offeature verifyandfeature finish, so a suite of any length is
safe. A feature whose lead stopped is taken over only after the lease ran out and with your words, which are audited.
Records are local to the host unless the project switches to the shared backend (marshal enable). -
feature start|merge|sync|verify|finishandlocal prepare --base feature/Xask the marshal first and refuse when another
live lead holds the feature;feature startrecords the starter as lead,finishmarks the record finished,feature statusends with the marshal's view andfeature listshows each lead. A marshal that is absent or fails never blocks.
local-runs.jsonllines gainlead. -
The session-start hook lists the open features as data for the lead session. The guard keeps members from the mutating
marshal verbs, from the statefeatures/directory and from settingQARGI_LEAD. -
qargi release starthas a preflight. Before it creates the branch it checks what a release must update and refuses,
changing nothing, with a message naming the file and the fix: a man page (man/*.1) needs a.THline with a date and a
version field, and the first commit now sets them to the release's date andVERSION; aCHANGELOG.mdneeds a
## [Unreleased]section with content (--allow-empty-noteswaives that). Projects without a man page or changelog are
not checked for that part. -
Roles. A role is a directory with
role.json(its class,writeorread-only, and a description) andROLE.md(its
instructions).build,write,reviewandtestship inroles/; add your own under~/.qargi/config/roles/NAME/
(one lower-case token, neverlead, never a built-in's name).qargi role list|show|prompt|check. A local task names its
role (qargi local prepare --role R, which records the class inRUN/class;--abilitystill works), the task block
carries the role's text,qargi agent add --abilitiesandqargi agent fortake any role (a role of yours without a member
falls back to a member of the built-in role of the same class), and a cloud agent of a role gets its text in its system
prompt. The class, not the namereview, decides what the guard allows and which cloud tools are off. -
qargi local clean RUNremoves a collected, verified local run (clone, bare copy, output) and its private temporary
directory.qargi local preparemakes that directory (TMP, on/dev/shmwhen it exists,QARGI_RUN_TMPmoves it) for
the agent's test sandboxes, so parallel runs never share files and a run leaves nothing behind. The agent contract asks for
targeted checks per task (the full suite belongs to the coordinator after a collection), and the task skill describes
dispatching non-overlapping tasks in parallel. -
Methodologies. A methodology is the way a project is developed and released, as data: branches (long-lived, release
feature/<version>, taskagent/<slug>), versioning and changelog, test tiers (targeted per task, the whole suite once per
collection), CI, release steps, deployment options with instructions, and the generic files a new project starts with
(README, VERSION, CHANGELOG, CONTRIBUTING, CLAUDE.md, .gitignore, a GitHub Actions test workflow).gitflowships in
methodologies/; add your own under~/.qargi/config/methodologies/NAME/.qargi methodology list|show|check|files|deployment
only read; the scaffold carries no reference to qargi. -
qargi project attach [DIR]attaches qargi to an existing repository without changing it. It reads the remote, branches, tags,
version and changelog files, test command and CI, prints the answers it would store, the gaps against the methodology and
what it could not determine, and a plan token; with--planand--approvedit stores the answers outside the repository.
The safe gaps are closed byqargi project adopt, the rest by hand. -
qargi project new NAMEstarts a project from a methodology: it prints a plan (directory, branches, files, deployment
options with instructions) and a token; with--planand--approvedit creates the directory, runsgit init, writes the
generic files in a first commit and creates the long-lived branches, leaving you ondevelop. With--urlthe qargi answers are
stored too. Nothing is pushed and no remote is created.--deployment IDrecords a deployment option and prints how to do it.
The generated.gitignoreexcludes.claude/worktrees/and.claude/settings.local.json. -
Git-flow, as its author described it.
qargi feature start|list|sync|merge|status|verify|finish: a feature is a broad, related branch
cut fromdevelop; verified task branches are merged into it with--no-ff; the whole suite runs once when it is complete, and
only then is it merged intodevelop(one merge per feature). Several features can be open at once;feature listshows their
purposes and the files two of them both change.qargi release start|status|verify|push|finish VERSION [--hotfix]:
release/<version>fromdevelop(a hotfix frommaster), the version bump as its first commit, a pull request intomaster
so CI runs on the commit that will be released, then merge intomasterwith--no-ff, an annotated tag, merge into
develop(a hotfix: into the open release branch), delete, push. Merges are made in temporary worktrees and a branch moves only
after every merge succeeded; a conflict changes nothing, keeps the merge in progress in a worktree it names (exit 3), and
--resolvedapplies the merge you resolved. Merging and pushing need a plan token and an approval; a release starts only from
adevelopwhose head passed the whole suite. A finished feature's whole-suite run carries over todevelop's new head, and
a feature must containdevelopto finish, so a release needs no extra run. A release or hotfix finishes only on the commit that is
on origin with passing checks, and pushes master, develop and the tag together or not at all. -
The
feature finishandrelease finishplans list the commits and files being merged, so the approval is informed. -
The
qargi-flowskill: the lead's git-flow process with the qargi commands (features and tasks, the one whole-suite run per feature,
releases, hotfixes, resolving conflicts). A session that leads is pointed at it when it starts. -
qargi review apply RUN_DIRputs a collected run on a task branch of the project's repository: it needsreview checkand
local verifyto pass, createsagent/<slug>(or--branch) at the commit the base had when the run was prepared and applies
the patches withgit amin a temporary worktree, so your checkout is never touched. A patch that does not apply removes the
branch again; a run is applied once.qargi review prune [--yes]lists, or deletes, theagent/*branches already merged into
developor afeature/*branch. -
qargi packs apply --target claude-code PROJECTrenders the skills and tools a project has enabled into a managed state
directory,$QARGI_STATE/claude/PROJECT, replacing the previous render atomically, and prints the exact
claude --add-dir ...line that loads it. It needs no--asked; without--approvedit prints a plan token. Skills render
under.claude/skills, tool packs asmcp.jsonandsettings.json, with a manifest. Claude Code cannot enforce role scoping,
so the render is the union of the project's roles and role scoping is advisory there. Nothing is written into a repository or
into~/.claude.qargi packs check --target claude-code PROJECT(read only) exits 1 on drift: a changed or unreviewed pack,
a tampered, extra or missing rendered file, an enablement change, a rendered skill shadowed by~/.claude/skillsor the
checkout's.claude/skills, or a missing manifest.--target managed-agentsis the existing cloud update of an instance. -
qargi packs apply --target claude-coderefuses at plan time, naming the pack and writing nothing: aSKILL.mdwhose name
differs from the pack name or whose front matter is not closed or has twonamekeys, a skill and a tool with the same name,
and a tool allowlist name outside letters, digits,_,.and-. Each plan stages into its own hidden directory under a
lock, so concurrent applies serialize and the second refuses if the render changed meanwhile. -
qargi packs check --target claude-codealso reports a rendered file that differs from the library copy, a changed file mode,
a group- or world-writable render, a malformed manifest, and a manifest naming another project or with role scoping other
than advisory. -
qargi local prepareprints a WARNING block to stderr when the project's Claude Code render has drifted (the project is found
by matching the repository against the stored answers), with the findings and the fix,qargi packs apply --target claude-code PROJECT. The run goes on; stdout and the TASK-BLOCK PATHS block are unchanged. -
The guard protects that directory: members can no longer write under the state's
claude/directory, and the operands of
packs renderare judged as write destinations. -
A GitHub Actions workflow runs the whole test suite on pull requests and on pushes to
develop. -
qargi packs load [PACK] --role R [--project P]: read-only. Without a pack it lists what the role has enabled, with each
description; with one it prints its approved text and the library path of its other files. It reads the links when called,
so linking, unlinking, enabling and disabling take effect at once, and it refuses a pack that fails its review or changed
since it was approved. Members may run it. -
qargi upgrade [--branch B | --tag T]: plan, then apply with--plan TOKEN --approved "...": moves the installed tool (the root-owned checkout
install.shrecorded) to a newer branch (fast-forward only on its current branch) or tag of its origin, re-runs
install.sh --userand lists the members to refresh. The writing git commands run throughsudo; members cannot use the verb. -
qargi cloud list|show|set|unset|check|login: bind a project to anantprofile and the workspace it must reach
(the project's optionalcloudanswer). Every command about that project then runsantunder that profile,
and a cloud call is refused if the profile no longer reaches the workspace; a conflictingANTHROPIC_PROFILEis
refused. Projects without a binding are unchanged. qargi never reads or writes a token:loginruns
ant auth loginon your own terminal, and members cannot useset,unsetorlogin; the guard also protects
~/.config/anthropic. -
qargi mark SID applied|rejected --why CODErecords a reason (codes inlib/reasons.json);qargi reportcounts them.
marknow refuses a session the tracker does not know. -
qargi noticed list|resolve: collecting a session records thenoticed_not_acted_onnotes of its manifest
(short, secret-looking strings redacted, once each) in the append-onlyevents.jsonlbeside the audit log;
each stays open until given a disposition (followup, dismissed with--why, accepted, superseded);
qargi reportshows how many are open and how old the oldest is, never the text. -
qargi agent refresh NAME: re-render a member from the member definition qargi ships now, keeping its
name, abilities and model, so members created before a change (such as the hardened hook) can catch up
without being removed and re-added. -
qargi memory split|merge|copy FROM TO: move memory between two stores, each a directory of
notes, a.jsonldump or amemstore_id. Nothing is deleted: what a split archives goes to
/_archive/<date>/and a collision to/_conflicts/<date>/, with the origin of every note
written added to itsSources:line, so each change can be undone (merging a split's target
restores the archived originals byte for byte). Without--approvedthey print the plan and its
token and change nothing; a store whose notes changed since the plan is refused and left as it
was. On a directory store qargi's own writers are serialised by an exclusive lock, and each write
re-reads the note immediately before replacing it or releasing its name, so a change made by an
editor in that instant is refused and kept, not overwritten; an editor that writes in the last
instant after that read is still not prevented (the lock is advisory), which is why the digest
check exists.lib/membackend.pyis the backend interface (directory, fixture dump and Managed Agents
store throughant) with one ops executor,lib/memplan.pythe pure planning;
lib/canon.pygainsmake_plan, the migration plancanon planprints, for reuse.
A.jsonldump is read-only (a source, never a target of split, merge or copy). A note named
with a leading dot or trailing white space is not a note, and a note the target cannot hold
(too many path segments or too large for a Managed Agents store) makes the plan refuse and name
it. The plan token is always required:QARGI_NESTEDdoes not stand in for it, and the audit log
records the token, the selector and every step, with a second line once the apply succeeded.
mergeandcopywithout a selector leave the source's/_archive/behind. A
provenance segment counts only when its digest matches the note it was added to./_archive/
is a tolerated folder of canon 2 (canon checkwarns about a note there without our segment).
Known limit:canon applyis not run through the new executor;memplan.migrateexists for it. -
qargi report [--since DATE] [--instance NAME] [--stale-after D] [--local-stale-after D] [--runs-root DIR] [--json]: a read-only report from the session tracker (spend and spend per applied session, sessions pending review oldest first, sessions that look stale, idle sessions by why they stopped, time from creation to close) and from local run directories (finished DONE or BLOCKED, no manifest and still changing, no manifest and quiet: possibly stalled). It states what it cannot tell and never prints a session's note or request. -
qargi local prepareappends one JSON line per run (run directory, slug, ability, base, start time) tolocal-runs.jsonlin the state directory, soreportcan list local runs. -
instances refresh-prompt --if-stale: does nothing, with no cloud call, when the prompt rendered now has the hash recorded at the last provision or refresh. The registry entry of a cloud instance gets apromptobject (sha,skill,at);instances listmarks a changed promptprompt STALE, andinstances showsays which part changed. An entry without a hash (older release, orinstances init) is unknown, not stale. -
qargi supervise tick|status|nudge|delivered|hooks: the first version of the stalled-agent supervisor. Hooks only record; one idempotent tick (the only writer ofruns.json, under a lock) folds the per-run event files, the local-run registry and the session tracker, classifies every unfinished run in a fixed order (waiting on an approval, API stop failure, interim with a cap, looping on three identical tool digests, suspected dead on stale activity; cloud:requires_action,budget_reached, stale while running, idle awaiting review) and acts only by printingQARGI SUPERVISE <class> <run> <next-action>lines, appending tosupervisor.logand the audit log (originsupervisor), and preparing a nudge innudges.jsonl. A nudge is a fixed template, at most 2 per run with at least 10 minutes between them, never while the run waits or has little budget left, and never an approval; a local one is delivered by the coordinating session and counts onceqargi supervise delivered KEYrecords it, a cloud one is sent only byqargi supervise nudge SID --asked .... Nothing is sent automatically (a standing permission is a documented extension point, off). Thresholds are data inlib/supervise-defaults.json: conservative floors untilqargi reportshows real run lengths.statuswarns when the last tick is older than twice the interval. -
qargi hook subagent-start|subagent-stop|tool-use|tool-failure|notification|stop-failure|pre-compact: handlers for the Claude Code hooks that append one small line (ids, times, the tool name and a hash of its input; never a command, message or error text) torun-events/<agent_id>.jsonlin the state directory. They exit 0 at once, even on malformed input.qargi supervise hooksprints the settings snippet; it never writessettings.json. -
qargi reporthas a short Supervisor section (suspected stalls by class, what waits on you, prepared nudges awaiting action) once a tick has run. -
The audit log may carry an
originfield (supervisor); the tracker row recordslast_processed_at(the session'supdated_at) on refresh. -
Sessions record
interrupt_sent_atwhenqargi stopsends the interrupt (an interrupted turn also ends withend_turn) andstop_event_idsforrequires_action. -
QARGI_HOMEreplaces the root~/.qargithat holdsconfig/andstate/;QARGI_CONFandQARGI_STATEstill win over it. -
qargi migrate home: copies the data from the earlier XDG directories to~/.qargi/configand~/.qargi/state. Without--approvedit prints the plan (every directory, file and link with mode and digest, the*.lockfiles it skips, the files in which it rewrites old absolute paths: a project's credential file,local-runs.jsonl, anything else naming the old directories; the recordsaudit.log,supervisor.logandrun-events/are copied byte for byte and the plan lists them on a "Copied verbatim (records)" line) and a plan token covering it, and changes nothing. With--plan TOKEN --approved "<words>"it copies (the old directories stay as a backup), keeps modes (credentials 0700, files 0600), checks every file by digest, removes what it made if a step fails, refuses when the new root exists and is not empty, and logs anaudit.logline. Run again it says there is nothing to do. -
Dev runs:
install.sh --userrecords the tool it installed in<config>/install.json(--uninstallremoves it;--projectwrites nothing). A checkout run from any other place, with none ofQARGI_HOME,QARGI_CONFandQARGI_STATEset, keeps its data in<checkout>/.qargi(git-ignored), prints oneqargi: dev run from ...line on stderr per command (none forhelp,version, completion, the guard and the run-event hooks), and never touches live data; with noinstall.jsona checkout behaves as the installed one.qargi migrate homerefuses in a dev run unless a location is named. Seeqargi help dev. -
lib/paths.pyand the top oflib/lib.share the one place each language resolves these locations; the nine copies of the XDG logic are gone.
Changed
- The plan token of
packs apply --target claude-codealso covers file modes, the manifest records them, and the swap installs
only the tree the token approved. qargi local verifyandqargi local cleanaccept the lead's own work. After a passing verify the run recordsRUN/verified,
and later checks compare with it: fast-forwards ofdevelop,masterandagent|feature|release|hotfix/*branches and new
branches there are accepted, while remote refs, tags, deletions and rewrites still fail. A change now exits 2 (it was 1). Run
qargi local verifyon every run before merging any of them.qargi local prepareends its output with a blank line and aTASK-BLOCK PATHSblock (RUN_DIR,CLONE,OUT,TMP,GIT,
BASE_SHA); a caller that evals the output must stop at the blank line.qargi project attachreads the tree of the integration branch (develop, else the default branch, elseHEAD) and says which,
not the working tree. It prints origin as read and the normalised url. When answers are already stored it shows stored against
detected and the fields the stored file lacks, stays read-only and gives no plan token; with--forcethe plan keeps what it
cannot detect (the roles' models and effort, cloud, memory, budget).qargi feature startrefuses a name origin already has, asked live withgit ls-remote.qargi feature status|finishandqargi release status|push|finishask the live origin withgit ls-remotewhere the branches
are (QARGI_REMOTE_TIMEOUTseconds, default 10) instead of the last fetch, and printremote not checkedwhen origin cannot
be reached.tests/run.shruns without the caller's cloud binding or anyQARGI_*orANTHROPIC_*variable and with a freshHOME, and
every test is hermetic (tests/hermetic.sh,tests/hermetic.py): fresh qargi config and state, and failingantandclaude
stubs first onPATH.- The role and contract text lists the rules to follow before DONE. Every cloud agent's prompt changes: run
qargi instances refresh-prompt NAME --if-stalefor each. qargi feature verifyandqargi release verifyrun the project's test command without the project's cloud binding
(ANTHROPIC_PROFILE,QARGI_CLOUD_WORKSPACE,QARGI_CLOUD_PROJECT), andtests/run.shunsets them, so a project with
a cloud binding can get a passing whole-suite record.- The cloud agent contract, the member definition and the task skill speak of a role and its text instead of loading an
ability skill. Every cloud agent's prompt changes: runqargi instances refresh-prompt NAME --if-stalefor each. The - Breaking before 1.0: the default locations are
~/.qargi/configand~/.qargi/state, not$XDG_CONFIG_HOME/qargiand$XDG_STATE_HOME/qargi; the XDG variables no longer move qargi's data. While only the earlier directories exist, every command excepthelp,version, completion,__guard, the run-event hooks andmigrate homestops and asks you to runqargi migrate home; qargi never creates an empty~/.qarginext to old data, andinstall.sh --userdoes not record the install until then. - The member guard protects the pack library,
<config>/credentials/and<config>/install.jsonat the new location (the resolved configuration directory,$QARGI_HOME/config, the live one and~/.qargi/config) and keeps the earlier XDG paths protected as a backup. The rest of the configuration directory stays writable (the guard decides by path, not by qargi verb), and reading a protected path is still allowed. - The member guard refuses a member every skill-modifying verb:
qargi skill|tool new|import|seal|remove|unlink|link|enable|disable,qargi discover install,qargi packs applyandqargi import(found after wrappers, insh -c,evaland$(...), and whenpacks.shordiscover.pyis run directly), settingQARGI_NESTED, and writes under the pack library ($QARGI_CONF/packs, honouring the XDG defaults),~/.claude/skills,~/.claude/agents,~/.claude/pluginsand any.claude/skillsdirectory outside the run's clone (inside the clone it is the work product, reviewed as a patch; paths are resolved first, so a link in the clone to a protected location is still refused). Edit, Write and NotebookEdit are decided by the resolved path; Bash by a documented conservative heuristic (redirections, tee, cp, mv, rm, ln, install, rsync,sed -i,dd of=, find, tar and so on). The repository's ownskills/directory in a member's clone and its run directories stay writable. Read-only verbs (list,show,check,effective,search,render) are unchanged. A barrier, not proof; code that writes a file itself (python -c) is not covered. - The guard fails closed: an unexpected exception inside it is exit 2 with the reason on stderr, not a silent pass.
agents/member.mdsetsonFailure: "block"and atimeouton the hook, so a hook that cannot start, crashes, times out or exits other than 0 or 2 blocks the call (needs Claude Code 2.1.295 or later; an older one runs the call, per the hooks documentation). Frontmatter hooks of a project-level agent file run only once the workspace is trusted. QARGI_NESTEDno longer stands in for the plan token ofskill|tool new|import|seal|remove|link|unlink|enable|disableandpacks apply;import,sealandpacks applyalways need--plan, and an empty expected token is an error. Nothing nested them (discover installalready cleared it, provisioning only renders).--approvedremains recorded text: proof that a person approved is still the owner's chat approval.
Removed
- The four ability skills
qargi-build,qargi-write,qargi-reviewandqargi-testare gone: nothing loaded them. A member
follows the role text that comes with the task block (roles/<role>/ROLE.md), andqargi help roles,qargi help agent
and the manual page no longer name them.install.sh --userremoves the leftover links to them.
Fixed
qargi canon auditnow attributes a session of a cloud base (<project>-worker,<project>-reviewer) to the role recorded in the local
session tracker, so its cross-role writes are reported; a session it cannot attribute is counted once in a NOTE line, not guessed.qargi cloud show|check|login|unsetnow refuse--profileand--workspace-id(onlysettakes them) instead of ignoring them;
qargi agent for --surfacecompleteslocalandcloud; the test that keeps the help in step with the scripts now also covers
lib/provider.sh.- Read-only cloud roles now have the
writebuilt-in tool off as well asedit(a reviewer could still create files through
write); an unknown class now counts as read-only instead of write, andworkerandreviewerare reserved role names. qargi provision applyno longer fails on the second and later roles of a project: an empty package list became[""], which the shared environment update rejected, before the stores were attached and the instance registered.qargi memory split|merge|copy: a note whose ownSources:line is exactlyorigin not recorded (qargi memory)(written by an earlier copy or by hand) is no longer mistaken for the line qargi inserts into a note that has none. Undoing a copy or an archive (merging a split's target) now returns both kinds of note byte for byte; which one it was is read from the digest already in the origin segment, so the segment format is unchanged and notes written by earlier versions restore as before.- The tracker's
stop_reasonwas empty for every session: the session object has no such field.status,watch,send,closeandtracknow read it from the lastsession.status_idleevent of an idle session.watchcan now printbudget_reached.
Security
- A review member could lift its own read-only limit: the guard took the ability from
RUN/ability, a file the member could
write. The guard now refuses any write to a run'sabilityandrefs.before, and a member that only reviews names its
class in the hook command of its definition (under the protected agents directory), which holds on every task whatever the
run file says. Runqargi agent refresh NAMEfor existing members to get the new hook; a guard given an unknown class
refuses every call. - A member could rewrite the installed tool through the links in
~/.claude/skills(they resolve into the installed copy,
which was not a protected location) and a project's.claude/agentsdefinitions (which carry the hook that guards a
member). The guard now protects the installed tool root recorded ininstall.jsonand.claude/agentsoutside the run's
clone, as it already did.claude/skills. Reading stays allowed.