Starter packs slice SP8 (#1873): the owner saves an organization's shape as a template that later applies through SP4 as saved:<name>. Design: docs/plans/2026-11-12_starter-packs-design.md section 2 (the saved origin), section 5 and section 8 SP8.
packages/organization/src/template-save.mjs (new, plus a packages/business re-export). It captures the org, strips credential material, and replaces org, project, owner, agent and root names with placeholders in one regex pass, in free text only. It scans the kept text for held credentials, and builds a preview with a digest. Stripped: instance credentials, copyBindings, copyId, orgIncarnation, generation. Role credential request lines are kept. A held value in kept text refuses template-secret-suspected (new refusal with a table entry) and names the field path, never the text. Save is O_EXCL|O_NOFOLLOW 0600 under the caller's account directory. It refuses group- or world-writable dirs, symlinked account dirs, a second save to the same name, a non-pack-id name, a ninth hire and a stale digest. Each packs entry is only {id, version}.
Bus: runtime save/list ops call the organization module. The broker never imports it, so the sandbox import closure pin holds. Verbs: template.save, template.list and their .console forms. VERB_RIGHTS is null for both .console verbs, so they are owner-only. A member or agent session refuses human-required. #templateFail runs the secret check on the whole reason, then cuts it to 300 characters.
CLI: mosaic org template save ID NAME [--project P] [--preview | --digest D] and mosaic org template list ID. Refusal hints map from the code.
WebUI routes (no page in this slice): GET /api/orgs/<id>/templates, POST .../templates/preview, POST .../templates (needs the digest). Root owner only, sign-in, same-origin, the session is re-checked after the body is read, read-only without --send. Same admission as packs-http.
Tests: new organization template-save (17), bus templates (9), cli org-templates (2), webui template-http (5). The org-rights, console-decide and request-console pins moved with the new verbs. Red before is recorded in the lane report. Lane gate on this head: 8125/2 over 768 files, plus test-config.sh and test-task.sh rc 0. The 2 fails are the CHAT-01 jsonschema base red. Lead check under env -i on this head (415 files: touched tests, importers of every touched src basename, refusal, redact, rename-b and project-runtime tests): 4650/1 plus 5 environment skips; the 1 fail is CHAT-01.
Reviews (fresh Opus 5.5 delegates): the build review and the security review both approved. Fixed in the review round: placeholder collision for an instance named root, org or agent (now one pass); the CLI hint never showed with the real transport; the pins and the rename-b business shim. Re-check 1 approved; two low findings were fixed (close in its own try before unlink; secret check before the cut). Re-check 2 approved that patch. The rebase onto a9d72b3cd was range-diff = for all three commits.
Deferred:
CLI and HTTP show the refusal code and hint, not the reason. Both transports carry only the code, so this needs a transport change.
packsCommand (packages/cli/src/org.mjs) rethrows the transport error and drops the pack refusal hint. SP4/SP5 code, same fault fixed here for templates.
No tests yet for the unlink after a failed write, the close-throws path, the reason drop in #templateFail, checkPack's message as the reason, or a held value straddling character 300.
A renamed hire keeps internal references to its old name. Overlapping literals resolve leftmost-first.
assertNotHeld does not scan SSH host key material. That gap predates SP8.
Starter packs slice SP8 (#1873): the owner saves an organization's shape as a template that later applies through SP4 as `saved:<name>`. Design: `docs/plans/2026-11-12_starter-packs-design.md` section 2 (the `saved` origin), section 5 and section 8 SP8.
- `packages/organization/src/template-save.mjs` (new, plus a `packages/business` re-export). It captures the org, strips credential material, and replaces org, project, owner, agent and root names with placeholders in one regex pass, in free text only. It scans the kept text for held credentials, and builds a preview with a digest. Stripped: instance `credentials`, `copyBindings`, `copyId`, `orgIncarnation`, `generation`. Role credential request lines are kept. A held value in kept text refuses `template-secret-suspected` (new refusal with a table entry) and names the field path, never the text. Save is O_EXCL|O_NOFOLLOW 0600 under the caller's account directory. It refuses group- or world-writable dirs, symlinked account dirs, a second save to the same name, a non-pack-id name, a ninth hire and a stale digest. Each packs entry is only `{id, version}`.
- Bus: runtime save/list ops call the organization module. The broker never imports it, so the sandbox import closure pin holds. Verbs: `template.save`, `template.list` and their `.console` forms. `VERB_RIGHTS` is null for both `.console` verbs, so they are owner-only. A member or agent session refuses `human-required`. `#templateFail` runs the secret check on the whole reason, then cuts it to 300 characters.
- CLI: `mosaic org template save ID NAME [--project P] [--preview | --digest D]` and `mosaic org template list ID`. Refusal hints map from the code.
- WebUI routes (no page in this slice): `GET /api/orgs/<id>/templates`, `POST .../templates/preview`, `POST .../templates` (needs the digest). Root owner only, sign-in, same-origin, the session is re-checked after the body is read, read-only without `--send`. Same admission as packs-http.
Tests: new organization template-save (17), bus templates (9), cli org-templates (2), webui template-http (5). The org-rights, console-decide and request-console pins moved with the new verbs. Red before is recorded in the lane report. Lane gate on this head: 8125/2 over 768 files, plus `test-config.sh` and `test-task.sh` rc 0. The 2 fails are the CHAT-01 jsonschema base red. Lead check under `env -i` on this head (415 files: touched tests, importers of every touched src basename, refusal, redact, rename-b and project-runtime tests): 4650/1 plus 5 environment skips; the 1 fail is CHAT-01.
Reviews (fresh Opus 5.5 delegates): the build review and the security review both approved. Fixed in the review round: placeholder collision for an instance named root, org or agent (now one pass); the CLI hint never showed with the real transport; the pins and the rename-b business shim. Re-check 1 approved; two low findings were fixed (close in its own try before unlink; secret check before the cut). Re-check 2 approved that patch. The rebase onto a9d72b3cd was range-diff `=` for all three commits.
Deferred:
- CLI and HTTP show the refusal code and hint, not the reason. Both transports carry only the code, so this needs a transport change.
- `packsCommand` (packages/cli/src/org.mjs) rethrows the transport error and drops the pack refusal hint. SP4/SP5 code, same fault fixed here for templates.
- No tests yet for the unlink after a failed write, the close-throws path, the reason drop in `#templateFail`, checkPack's message as the reason, or a held value straddling character 300.
- A renamed hire keeps internal references to its old name. Overlapping literals resolve leftmost-first.
- `assertNotHeld` does not scan SSH host key material. That gap predates SP8.
template-save.mjs captures the org (or one project) as a starter-pack JSON under
<config>/templates/<owner>/<name>.json: copy material and instance credentials
stripped, role credential request lines kept, owner/org/project/agent/root names
replaced by placeholders in free text, at most 8 hires, packs entries {id, version}.
A held credential value in kept text refuses template-secret-suspected naming the
field path. Preview then save with the preview's digest; O_EXCL 0600 write, a
second save refuses.
Bus: template.save/template.list for the owner's CLI cap, .console names for the
owner's Console cap, null in VERB_RIGHTS. CLI: mosaic org template save|list.
Console: GET /api/templates, POST /api/templates/preview, POST /api/templates.
- template-save: one alternation pass replaces every literal, so an
instance named root, org or agent never rewrites a placeholder already
written in. checkPack's refusal message is passed on as the reason. A
write or fsync failure removes the partial file it created.
- broker #templateFail drops a reason the credential check refuses.
- cli template words: humanTransport throws a CliError named by the bus
code; a known code now gains its hint (the test transport throws the
same CliError).
- template-http: the header notes serve.mjs strips /api/orgs/<id>.
- pins: the two .console verbs in console-decide and request-console;
the packages/business/src re-export for template-save.mjs.
- tests: placeholder collision, a held-value key masked as [key], and a
save after a real pack.apply.console keeping {id, version}.
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Starter packs slice SP8 (#1873): the owner saves an organization's shape as a template that later applies through SP4 as
saved:<name>. Design:docs/plans/2026-11-12_starter-packs-design.mdsection 2 (thesavedorigin), section 5 and section 8 SP8.packages/organization/src/template-save.mjs(new, plus apackages/businessre-export). It captures the org, strips credential material, and replaces org, project, owner, agent and root names with placeholders in one regex pass, in free text only. It scans the kept text for held credentials, and builds a preview with a digest. Stripped: instancecredentials,copyBindings,copyId,orgIncarnation,generation. Role credential request lines are kept. A held value in kept text refusestemplate-secret-suspected(new refusal with a table entry) and names the field path, never the text. Save is O_EXCL|O_NOFOLLOW 0600 under the caller's account directory. It refuses group- or world-writable dirs, symlinked account dirs, a second save to the same name, a non-pack-id name, a ninth hire and a stale digest. Each packs entry is only{id, version}.template.save,template.listand their.consoleforms.VERB_RIGHTSis null for both.consoleverbs, so they are owner-only. A member or agent session refuseshuman-required.#templateFailruns the secret check on the whole reason, then cuts it to 300 characters.mosaic org template save ID NAME [--project P] [--preview | --digest D]andmosaic org template list ID. Refusal hints map from the code.GET /api/orgs/<id>/templates,POST .../templates/preview,POST .../templates(needs the digest). Root owner only, sign-in, same-origin, the session is re-checked after the body is read, read-only without--send. Same admission as packs-http.Tests: new organization template-save (17), bus templates (9), cli org-templates (2), webui template-http (5). The org-rights, console-decide and request-console pins moved with the new verbs. Red before is recorded in the lane report. Lane gate on this head: 8125/2 over 768 files, plus
test-config.shandtest-task.shrc 0. The 2 fails are the CHAT-01 jsonschema base red. Lead check underenv -ion this head (415 files: touched tests, importers of every touched src basename, refusal, redact, rename-b and project-runtime tests): 4650/1 plus 5 environment skips; the 1 fail is CHAT-01.Reviews (fresh Opus 5.5 delegates): the build review and the security review both approved. Fixed in the review round: placeholder collision for an instance named root, org or agent (now one pass); the CLI hint never showed with the real transport; the pins and the rename-b business shim. Re-check 1 approved; two low findings were fixed (close in its own try before unlink; secret check before the cut). Re-check 2 approved that patch. The rebase onto
a9d72b3cdwas range-diff=for all three commits.Deferred:
packsCommand(packages/cli/src/org.mjs) rethrows the transport error and drops the pack refusal hint. SP4/SP5 code, same fault fixed here for templates.#templateFail, checkPack's message as the reason, or a held value straddling character 300.assertNotHelddoes not scan SSH host key material. That gap predates SP8.template-save.mjs captures the org (or one project) as a starter-pack JSON under <config>/templates/<owner>/<name>.json: copy material and instance credentials stripped, role credential request lines kept, owner/org/project/agent/root names replaced by placeholders in free text, at most 8 hires, packs entries {id, version}. A held credential value in kept text refuses template-secret-suspected naming the field path. Preview then save with the preview's digest; O_EXCL 0600 write, a second save refuses. Bus: template.save/template.list for the owner's CLI cap, .console names for the owner's Console cap, null in VERB_RIGHTS. CLI: mosaic org template save|list. Console: GET /api/templates, POST /api/templates/preview, POST /api/templates.- template-save: one alternation pass replaces every literal, so an instance named root, org or agent never rewrites a placeholder already written in. checkPack's refusal message is passed on as the reason. A write or fsync failure removes the partial file it created. - broker #templateFail drops a reason the credential check refuses. - cli template words: humanTransport throws a CliError named by the bus code; a known code now gains its hint (the test transport throws the same CliError). - template-http: the header notes serve.mjs strips /api/orgs/<id>. - pins: the two .console verbs in console-decide and request-console; the packages/business/src re-export for template-save.mjs. - tests: placeholder collision, a held-value key masked as [key], and a save after a real pack.apply.console keeping {id, version}.