Skip to content

Steward preset: the Automated Environment of an Organization persona (decision 0169, DEV-6632 M2) - #106

Merged
immakermatty merged 3 commits into
mainfrom
claude/DEV-6632-steward-preset
Sep 30, 2026
Merged

immakermatty merged 3 commits into
mainfrom
claude/DEV-6632-steward-preset

Conversation

@immakermatty

@immakermatty immakermatty commented Sep 29, 2026 •

Copy link
Copy Markdown
Contributor

Why

Upstream decision 0169 adds a fourth kind of Environment next to the three of 0165: Automated. An Organization's automated work is done by a bot team of its persona in Lazurio MausBot (Lazurio's fork of OpenMausBot). The Environment is an Organization work VM with one responsible operator (an Owner or Admin). Its GitHub identity is the persona's own machine GitHub user account, not the operator's account and not Lazurio for GitHub. This PR is the Platform part of milestone M2 of plan DEV-6632: the workspace preset for that Environment.

Target state

hosted-organization-steward, a fifth preset that follows the naming of the other three hosted presets:

Machine kind workspace-vm
Operator / Principal the one responsible operator (Owner or Admin); only the operator uses SSH, for service interventions; colleagues work with the persona through GitHub
Personalspace never; Organization repositories are mounted under organizations/<org>/ as on the other Organization presets
Provider identity new persona-account: the persona's own machine account, signed in to gh by the operator, who holds its 2FA and recovery codes
Surfaces launchpad, hosted-entry (already carries T3 Code), new openmausbot
Supervision OS service manager
Bot team (new field botTeam, null on every other preset) OMB_DEFAULT_BOT_CWD = the Lazurio Folder; the team is lazurio/teams/steward.openmaus.json from the installed release; the GitHub intake is on for the team leader, with scope organization, owners = the handover's Organization, and the Organization's infra and productionspace repositories excluded

The preset only declares the bot-team values. The service that installs and runs Lazurio MausBot applies them (a Machines workload today), and Platform applies none of them. The Folder renders them in two places: a short "Persona bot team" section in AGENTS.md and a settings table in manual/this-machine.md. Those sections also state the identity rule and the publication rule: publish only a PR assigned to the persona with an explicit /lazurio publish instruction, and a person approves the persona's own PRs.

Deriving the kind. It comes from a typed handover value, never from names. The value is a third owner.assignment kind, {kind: "automation", github_login, github_id}, which names the responsible operator exactly the way operator does. A stored binding accepts it (githubLogin, githubId) and derives the Steward preset. Any other shape still fails closed.

The vendored handover schema is not changed locally (F10 rules that out). So until Machines adds the value and Platform re-pins, a handover that declares it is refused whole (machine-context-invalid), and the operator picks the preset explicitly with folder-init --preset hosted-organization-steward. That lets the M3 pilot run on today's work-VM handovers without waiting for Machines.

Allow-list. Every workspace-vm now allows all three Organization presets, the same kind-only rule F10 already uses. I rejected the alternative of allowing Steward only on an automation handover, for two reasons:

  • Nothing could choose the preset before Machines ships the value.
  • A VM re-assigned from team to automation could not reach Steward through the change path, because the recorded binding would refuse it.

A test covers the re-assignment path: refresh reports preset-derivation-changed, then profile-update --preset hosted-organization-steward, then refresh succeeds.

What does not change

  • For every handover that exists today, the derivation, the recorded state and the rendered bytes are identical. All 37 existing snapshots pass unchanged (the snapshot diff only adds lines), and the template revision stays base-instructions-13. Existing Folders therefore see no re-render and no drift.
  • The one visible change for existing work VMs: the allow-list (the preset-ambiguous output, /api/profile, the Launchpad selector) lists a third choice.
  • The vendored schema and its provenance are untouched, and so is the src/machine/binding.ts projection. persona-account does not trigger the Team gate (githubActionRefused), so gh sign-in and SSH key linking stay offered.
  • Launchpad code and routes are unchanged except one label (Automated / Automatizovaný). Without it the new option would appear under the generic "Workspace preset" label.

Two small consumers follow the new assignment kind:

  • src/recover/private-values.ts now withholds the responsible operator from recovery evidence, as it already does for an assigned operator. Without this change the login would have leaked into a recovery issue.
  • The Launchpad's This Machine view shows the operator the same way it shows an assigned operator (no code change there).

Wording (issue #99). Every user-facing string this PR adds says "Environment" / "Remote Environment", never Machine, Mašina, VM or server. That covers the Folder text in cs and en, the Launchpad label and the gh instruction in docs/environment-tools.md. Czech uses the masculine form ("Automatizovaný Environment"). The persona's account is called "a bot account". Identifiers, keys and command names keep machine, and pre-existing lines are untouched. A test keeps the preset's added sections free of those words.

Verification

Tests were written first on the real consumers: preset data, binding, folder-init, refresh, rendering and the gh gate. Before the implementation, all five targeted files failed on Invalid Machine assignment. After it:

  • bun run check (lint, typecheck, bun test, check:public, build:proof, smoke:proof) on HEAD 07512b1 (base a9e195f): exit 0; 1065 pass, 7 skip, 0 fail, 42 snapshots (37 match main exactly, plus 5 new steward snapshots; the snapshot diff against main adds lines only).
  • New or extended tests:
    • the whole Steward composition, and the four earlier presets checked field by field;
    • the derivation table, with automation both with and without owner.team;
    • fail-closed refusal of every other assignment shape;
    • the vendored schema refusing automation today;
    • folder-init: derived on the automation binding, explicit on today's operator and Team handovers, refused on a personal VM and on a used personalspace/;
    • refresh after a re-assignment;
    • the gh gate for every preset;
    • recovery private values;
    • rendered persona/bot-team lines that appear only on this preset.
  • No native run on a real VM yet.

Base, decision and template revision. The PR is rebased on main at a9e195f (after #103). The Platform decision is F27 (docs/decisions.md), with a one-line pointer left in F10.

The Folder template revision stays main's base-instructions-14. The added text renders only under the new preset, which no earlier release can record. So every Folder of the four earlier presets keeps its bytes and recorded digests, and no existing Folder is re-rendered. A bump would rewrite all 37 existing snapshots and re-render every Folder with no change in content. Only the 5 steward snapshots are new; the other snapshot entries match main exactly.

Risks and open questions

  1. Machines handover change needed: the automation value in lazurio.machine.v1 plus a Platform re-pin and projection (HumanAndMachine-ai/Machines#273, private). Until then the preset is only an explicit choice.
  2. Explicit choices on a Team-assigned VM (both Work and Steward) are allowed by the kind-only allow-list; narrowing them is tracked separately in Narrow explicit Organization preset choices on Team-assigned work VMs (decision 0168) #107 and is not part of this PR.
  3. The persona account is not in the handover. The rendered rules say an account other than the persona's is a finding, but Platform cannot compare accounts. Should Machines also carry the persona's github_login / github_id?
  4. Team file inside the release archive: tracked in Ship the Steward team file inside the release archive OpenMausBot#4. Until it ships, "import from the installed release" has nothing to import.
  5. Who applies the bot-team defaults (the environment of the MausBot unit on an Automated VM) is not decided here. The preset declares them, and the rendered manual tells agents to report any difference to the operator.
  6. Which approval level an unattended team may run on is an open security decision of DEV-6632 and stays out of this preset.
  7. purpose stays human (a person answers for every Machine per 0169). The vocabulary sweep under 0156 is a separate step.

No release, tag or merge is part of this PR.

🤖 Generated with Claude Code

immakermatty and others added 3 commits September 30, 2026 01:49
…(decision 0169, DEV-6632 M2)

A fifth workspace preset, hosted-organization-steward, for the fourth kind
of Environment of upstream decision 0169: an Organization work VM with one
responsible operator whose GitHub identity is the persona's own machine
account, and whose bot team runs in Lazurio MausBot.

- Preset data: Personalspace never, Organization repositories mounted,
  provider identity persona-account, surfaces launchpad, hosted-entry and
  openmausbot, OS service manager, and a new botTeam field declaring the
  Lazurio MausBot defaults (OMB_DEFAULT_BOT_CWD = the Lazurio Folder, the
  Steward team file of the installed release, the GitHub intake for the
  team leader in the Organization scope without infra and productionspace).
  The four earlier presets are unchanged apart from botTeam: null.
- Derivation: a stored binding accepts owner.assignment
  {kind: "automation", githubLogin, githubId} (the responsible operator) and
  derives the Steward preset; every other kind still fails closed. The
  vendored handover schema is not changed: until Machines carries the value
  and Platform re-pins, the preset is an explicit choice, allowed on every
  workspace-vm like the other two Organization presets.
- Rendering: AGENTS.md and manual/this-machine.md state the persona identity,
  the bot team and its configuration and the publication rule, only for
  this preset; every earlier snapshot and the template revision are
  unchanged.
- The curated gh sign-in stays offered (for the persona's account); the
  responsible operator is withheld from recovery evidence like an assigned
  operator; the Launchpad labels the preset "Automated".
- Docs: workspace presets, F10 amendment, handover, environment tools,
  architecture.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The Folder text, the Launchpad label and the user-facing docs added for the
Steward preset say "Environment" / "Remote Environment", never Machine,
Mašina, VM or server; Czech uses the masculine form ("Automatizovaný
Environment", label "Automatizovaný"). The persona's account is "a bot
account" instead of "a machine account". Pre-existing lines are unchanged.
A test keeps the preset's added sections free of those words.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The F10 amendment becomes decision F27 (F25 and F26 are taken), with a
pointer left in F10 and a link from the workspace presets. The Folder
template revision stays main's base-instructions-14: the added text renders
only under the new preset, so every earlier Folder keeps its bytes and no
existing Folder is re-rendered. The steward snapshots are regenerated on
this base; every other snapshot is exactly main's.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@immakermatty
immakermatty force-pushed the claude/DEV-6632-steward-preset branch from c356dab to 07512b1 Compare September 29, 2026 23:57

@agentrozjedemeai agentrozjedemeai left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@immakermatty — APPROVED on exact head 07512b1 (DEV-6632 M2 / F27).

I traced the new preset, typed stored binding and current handover-schema refusal, explicit/derived initialization and reassignment, gh Team gate, recovery-value redaction, and cs/en Folder rendering. On this detached head, the seven targeted files passed (147/147); bun run check passed (1065 pass, 7 skip, 0 fail, 42 snapshots, plus public check, proof build and smoke). GitHub CI succeeded on ubuntu-24.04 and macos-14. git diff --check is clean.

I challenged the unchanged base-instructions-14: all 37 pre-existing snapshot entries are byte-identical to main and only five Steward entries were added; the new rendering is gated by a preset no older release could have recorded, so a global template bump is not warranted.

Scope limits remain explicit, not pilot qualifications: Machines#273 must deliver/re-pin the automation handover; Lazurio/OpenMausBot#4 must ship the team file and its service must apply the declared defaults; LazurioPlatform#107 must close the Team-assignment explicit-preset identity loophole before real Team-VM sign-in is considered safe. The persona account is not checked by Platform, and no native Automated VM run was provided. This review approves the bounded Platform declaration and rendering, not an end-to-end deployment or access change.

@immakermatty
immakermatty merged commit 5d6ddfc into main Sep 30, 2026
3 checks passed
immakermatty added a commit that referenced this pull request Sep 30, 2026
…nment wording; this decision becomes F28

- docs/decisions.md: main's F27 (the Steward preset) kept exactly; this
  branch's decision renumbered F28 after it (render.ts comment and the
  guard test follow).
- src/folder/render.ts: main's automation assignment line kept; the
  operator line stays masculine ("přiřazený Operátorovi").
- src/machine/cli.ts: main's help for hosted-organization-steward kept,
  "whether the Machine is assigned" says Remote Environment.
- tests/folder-handover.test.ts: main's allowed presets with this
  branch's next sentence.
- The guard now also renders hosted-organization-steward (automated
  handover); it passes without a new allowlist entry. Snapshots
  regenerated for every preset at base-instructions-15.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
immakermatty added a commit that referenced this pull request Oct 22, 2026
…h --message-file -; a key T3 Code refused is replaced (DEV-6676 P2)

T3 Code's acting-sender claim is out (Lazurio/t3code#106): an agent command
reads who it acts as from its environment and signs it into its own short
sessions. budíček's own `t3` now runs with T3CODE_ACTING_SENDER=budicek, so
the wake shows „budíček“; the marked seam `t3_session()` is gone. The
variable goes into that subprocess's environment alone, never into the
service's. `zadej` runs inside Buddy's environment, whose claim names him,
and T3 Code refuses `budicek` beside a name, so budíček's `t3` drops Buddy's
three variables.

The send follows T4 (#105) and the shared constants: `t3 thread send
<thread> --mode queue --idempotency-key <key> --message-file - --base-dir
~/.t3-buddy --json`. A positional `-` would have been the literal message.

T3 Code keeps a refusal for its key (a rejected receipt is final, #105), so
after a refusal T3 Code names, the next round sends with a new key
(`<key>-o1`, …), which cannot repeat a message that never went out; a lost
answer, a server that does not run or an unnamed failure keep the key.

Tests (41): the fake `t3` applies T3 Code's acting-sender rules and keeps
refusals per key; budíček's `t3` acts as budíček even inside Buddy's
environment, and nothing else it runs does; a refused key is never sent
again and the next one lands once; a lost answer keeps the key and the wake
lands once. Checked against T3 Code's own actingSenderFromEnvironment (#106
at d6e918c3): `budicek` alone is accepted, beside a name refused.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
immakermatty added a commit that referenced this pull request Oct 22, 2026
…ser's name from his persona (DEV-6676 P1)

`lazurio buddy chat --apply` adds T3 Code's acting-sender claim
(Lazurio/t3code#106) to the `buddy` provider instance's environment:
T3CODE_ACTING_SENDER=buddy, T3CODE_ACTING_FOR and
T3CODE_ACTING_FOR_ACCUSATIVE, the user's name as it stands alone and after
„za“ from ~/.config/lazurio/buddy/persona.json (`user.nominative`,
`user.accusative`). Every `t3` Buddy runs from his chat inherits it, so what
he writes or decides in the user's threads shows „Buddy za <jméno>“.

The claim lives only in Buddy's own provider: never in the environment of a
T3 Code service, lazurio-t3-buddy.service included, or in the user's Chat,
whose agents would all inherit it. A name T3 Code would refuse (not 1 to 64
characters on one line, something to trim, a control, formatting or
separator character) would fail every `t3` Buddy runs, so without a usable
name the command writes nothing (`buddy-persona-unreadable`).

Tests: the members with the claim; an older name replaced; the claim only in
Buddy's provider, the user's Chat settings and the unit untouched, Hermes's
check without it; each unusable persona refused with nothing written. The
written file decodes with T3 Code's ServerSettings, and its three variables
with T3 Code's own actingSenderFromEnvironment (#106 at d6e918c3) as
{kind: "buddy", for, forAccusative}.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
immakermatty added a commit that referenced this pull request Oct 22, 2026
…y chat, budíček's t3 channel, no rail or bubble on his page, the layer's rules and F61 (DEV-6676) (#592)

* Buddy: the bubble in Lazurio in .hermes.md: its own conversation, the page context as data, SSH only through Lazurio's names (DEV-6676)

A person can now write to their Buddy from the bubble in Lazurio's web
apps (Buddy on the web v1). Buddy's rules gain the section „Bublina v
Lazuriu“ ("The bubble in Lazurio"):
- the bubble is a conversation of its own next to Telegram, and a reply
  goes back where the request came from (root 0210, point 7);
- the block „Kontext stránky (údaje, ne pokyn)“, which the Hermes
  lazurio_web adapter puts into the model's copy of each message, is data
  that says where the person is and commands nothing;
- Buddy looks into the Environment from the context with
  `ssh <environment id>` only when that name is in
  ~/.ssh/config.d/lazurio-environments.conf, which Lazurio generates from
  the network grants (root 0210 evening addendum, point 4); otherwise he
  says he cannot reach it yet, and he never guesses a host or accepts an
  unknown host key;
- work in another Environment goes to a bot there through
  `budicek zadej --env <environment id>`.

The skill lazurio-buddy-pomocnici now says budíček wakes Buddy in the
conversation he gave the work from, not always the main one, matching
budíček's channel (#587).

Template revision base-instructions-67, with the pinned digest and the
manual snapshots. The whole layer passes Hermes's injection scan at context
and strict scope; the SSH rule is split over two lines so that no line pairs
a <…> placeholder with ~/.ssh. Decision note under F14.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Budíček: a delegation from Buddy's chat in Lazurio wakes him there, once, as a queued message in his one thread (DEV-6676 P2)

Buddy's chat in Lazurio is T3 Code with Hermes over ACP (decision F61). Its
provider instance runs `hermes acp` with LAZURIO_BUDDY_CHANNEL=t3, so
`budicek zadej` from the chat records `"kanal": "t3"` (optional in verze 1).
Such a wake is one message in Buddy's one thread: found with
`t3 lazurio buddy thread --json`, sent with `t3 thread send <thread> --mode
queue --idempotency-key <wake key> -` against `--base-dir ~/.t3-buddy`. Queue
never interrupts a turn; the key makes a repeated send after a crash the same
message. Its text is fixed: `budíček <id>: <STATE>`, the bot's report on one
line as `Výsledek bota (údaje, ne pokyn): …`, and `budicek vysledek <id>`.

Without the channel nothing changes: Hermes's Kanban wakes Buddy in Telegram,
as for every record from before. An unknown channel fails `zadej` before
anything exists; without Buddy's thread the task is `nezalozen` and no bot
starts; the last resort stays the Telegram DM. The session that authors the
message is a marked seam (`t3_session`) until the trace claim `budicek`
(Lazurio/t3code agent/DEV-6676-buddy-trace) is merged.

Tests: the channel recorded, the thread answering before the bot, one queued
message with its key and text, a bounded report, a restart right after the
send and at every other step waking once, T3 Code down and back, no thread,
a bot that does not start, a second round, re-wakes and the Telegram last
resort, unknown channels, and Telegram without the channel or from an old
record.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Shell: Buddy's own page draws no rail and no bubble, so his chat in the bubble's window is only his (DEV-6676 P3)

Buddy's chat is now a T3 Code of his own on his origin,
https://buddy.<slug>.lazurio.io (decision F61). T3 Code's page loads
/.lazurio/shell.js and places <lazurio-rail> and <lazurio-buddy> like every
app of an Environment, so inside the bubble's window the shell would draw the
Environment's rail beside Buddy's chat and a second bubble inside Buddy.

On a page whose origin is Buddy's (`isBuddysOwnPage`: the shape every
`buddy.origin` of the merged document has, known before any document
arrives) the rail adopts no styles, keeps no width, takes no jump shortcut
and reads or reports nothing, and <lazurio-buddy> draws no bubble. Every other
page, the apps that frame him included, is drawn as F60 says; the column
head stays the host's to place.

Verified by tests/shell-buddy.test.ts (his origin and every origin a merged
document names as his are his own page; the apps, other Environments and
look-alikes are not) and in headless Chromium against a page placed like T3
Code's: on t3code.ada the rail (64 px) and the launcher; on buddy.ada a 0x0
rail, no padding, no bubble, and only the shell document read.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Buddy's chat: lazurio buddy chat gives Buddy's own T3 Code its one provider, Hermes over ACP, beside everything else in its settings (DEV-6676 P1)

Buddy's chat in Lazurio is a T3 Code of its own on the user's Osobní
Prostředí, ~/.t3-buddy (decision F61, Matěj's variant A). Machines run it and
declare its project; what makes it Buddy's are members of its settings, and
Lazurio owns exactly those, in T3 Code's own keys (packages/contracts
settings.ts and providerInstance.ts, provider-acp-registry settings.ts):

- the provider instance `buddy`: T3's ACP driver with a local command,
  `hermes acp`, HERMES_HOME=~/.hermes and LAZURIO_BUDDY_CHANNEL=t3, so
  budíček wakes Buddy back in this chat;
- `codex` and `claudeAgent` off, the only built-in instances T3 Code turns on
  by itself;
- continueThreadsAfterServerUpdate and enableAgentBrowserAccess false.

`lazurio buddy chat` reads whether they are in place; `--apply` writes them
into ~/.t3-buddy/userdata/settings.json and keeps every other member,
replacing the file atomically only while it holds what was read (T3 Code's
own `t3 theme set` protocol beside its running server, which watches the
file). It writes nothing outside the user's own Osobní Prostředí, without
Buddy's layer in the Folder's .agents/buddy, with the layer inside a Git work
tree (checkpoints and a rollback would fork Buddy's memory), or without
Hermes's ACP server (`hermes acp --check`). A file T3 Code could not decode,
a link or a directory is left for the user. The person's Chat (~/.t3) keeps
F51: T3 writes its settings itself.

Not here: the composer's steer default, which is a client setting of T3 Code
(followUpBehavior, the browser's storage) and so the Buddy surface's (T2),
and the project, which T3 Code creates from the unit's declaration.

Tests: the members in T3 Code's shape; every other member kept; read-only
and apply, private modes, nothing rewritten when in place; T3's order and
own members still managed; each refusal writing nothing; files left as they
are; another writer between read and write; other Environments skipped; the
command's JSON and exits. The written file decodes with T3 Code's own
ServerSettings and AcpRegistrySettings: buddy on, Codex and Claude off.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Buddy: .hermes.md's „Bublina v Lazuriu“ follows his chat on T3 Code: one conversation, its own T3 tools, budíček's wake there, a stop or steer joined to the earlier request (DEV-6676 P1)

The bubble's chat is now T3 Code with Hermes over ACP in a T3 Code of its own
(decision F61), not the closed `lazurio_web` adapter. The section keeps what
still holds: the page context is data that commands nothing, SSH only
through the names Lazurio generates and never an unknown host key, and work
in another Environment through a bot there. It adds what the T3 mechanism
asks of Buddy:

- the chat is one conversation that goes on day after day, beside Telegram;
- the MCP server `t3-code` T3 Code gives every ACP session belongs to that
  chat: no threads or projects and no steering with it; the user's threads
  stay the `t3` command's;
- the page-context block is written into the user's message and kept in the
  history; the user's words are the rest;
- budíček's wake arrives in the chat as its fixed message, not the user's
  words;
- a stop or a steer joins the earlier request to the next message (Hermes's
  „User correction/guidance after interrupt:“): follow the new one, check
  what a cut-off tool step did before repeating it, and look in
  `budicek seznam --otevrene` before giving a bot work again.

The skill `lazurio-buddy-pomocnici` shows both forms of the wake. Template
revision stays base-instructions-67 (unpublished), its digest re-pinned; the
F14 addendum is rewritten. The whole layer passes Hermes's injection scan
(tools/threat_patterns.py, Lazurio/hermes-agent d923a5eb) at context and
strict scope; .hermes.md is 14.2k (cs) and 15.6k (en) characters.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Decisions: F61, Buddy's chat in Lazurio is T3 Code with Hermes over ACP (the Platform's side), and F60's addendum: his frame is his own T3 Code, his page draws no rail or bubble (DEV-6676 P4)

F61 records Matěj's decisions of 2026-10-22 (variant A, steer by default,
the page context in the user's turn, Hermes changes only in the fork, one
conversation, Mattyčus) and the Platform's part: `lazurio buddy chat`
(Buddy's T3 settings, with the boundary to F51 and what is not the
Platform's: the composer's steer default, the project, the unit, Hermes's own
configuration), budíček's channel `t3`, the layer and the shell. It retires
the frame parts of the F61 proposed in closed #587 (the Launchpad listener,
the runtime contract, the adapter proxy and secret, the frame page); its
wake back to the channel stands with T3's channel. Alternatives and the
follow-ups that wait for T3 Code's trace claims are named.

F60's addendum of 2026-10-22: Buddy's origin serves his T3 Code, the frame's
side is T3 Code's (T2), and the shell draws no rail and no bubble on a page
of Buddy's origin, known before any document arrives.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Buddy's chat: his instance's one switch is its enabled, and a file with comments is the person's (DEV-6676 P1)

T3 Code reads a false `enabled` inside an instance's configuration as off,
whatever the instance's own `enabled` says. Buddy's instance now keeps no
`enabled` in its configuration, so `--apply` always leaves him on; the test
of the members Lazurio owns covers it.

The refused files are named as they are: a file that is no plain JSON object
is left as it is, both one T3 Code could not decode and one with comments,
which T3 Code reads but a rewrite would drop (the code, F61 and the test).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Buddy's chat: a change of Buddy's T3 settings holds T3 Code's ownership of its home, so no server write is lost (Pablo's review of #592)

Pablo found the gap: comparing the file and then renaming over it are two
steps, so a running T3 Code server could write between the last comparison
and the replace, and that write would be lost while the command answered
`managed`. `t3 theme set` has the same gap; copying it proved nothing.

A change now takes T3 Code's own ownership of the home first: the exclusive
transaction on `server-owner.sqlite` (apps/server/src/serverOwnership.ts)
that its server holds for as long as it runs and that its offline commands
take before they change a home. Holding it, no server writes the file and
none starts until the replace is done; while Buddy's T3 Code runs, a change
is refused as `t3-running` and Machines stop its unit, apply and start it.
Settings already in place need nothing, so a converged apply passes while it
runs. The comparison before the replace stays, against a T3 command that
writes without the ownership, which Lazurio never runs on its homes.

Tests: a running server's ownership refuses a change and nothing is written;
settings in place need none while it runs; from the read to the replace, the
interval between the last comparison and the replace included, a server
starting in another process is busy; the home is owned again once the change
is done; an unlocked writer before the comparison is read again and kept.
Checked across runtimes too: while Node holds the lock exactly as T3 Code
does (node:sqlite, BEGIN EXCLUSIVE), Bun's attempt is busy. F61 and the help
say so.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Budíček: its wake in Buddy's chat is authored as budíček and sent with --message-file -; a key T3 Code refused is replaced (DEV-6676 P2)

T3 Code's acting-sender claim is out (Lazurio/t3code#106): an agent command
reads who it acts as from its environment and signs it into its own short
sessions. budíček's own `t3` now runs with T3CODE_ACTING_SENDER=budicek, so
the wake shows „budíček“; the marked seam `t3_session()` is gone. The
variable goes into that subprocess's environment alone, never into the
service's. `zadej` runs inside Buddy's environment, whose claim names him,
and T3 Code refuses `budicek` beside a name, so budíček's `t3` drops Buddy's
three variables.

The send follows T4 (#105) and the shared constants: `t3 thread send
<thread> --mode queue --idempotency-key <key> --message-file - --base-dir
~/.t3-buddy --json`. A positional `-` would have been the literal message.

T3 Code keeps a refusal for its key (a rejected receipt is final, #105), so
after a refusal T3 Code names, the next round sends with a new key
(`<key>-o1`, …), which cannot repeat a message that never went out; a lost
answer, a server that does not run or an unnamed failure keep the key.

Tests (41): the fake `t3` applies T3 Code's acting-sender rules and keeps
refusals per key; budíček's `t3` acts as budíček even inside Buddy's
environment, and nothing else it runs does; a refused key is never sent
again and the next one lands once; a lost answer keeps the key and the wake
lands once. Checked against T3 Code's own actingSenderFromEnvironment (#106
at d6e918c3): `budicek` alone is accepted, beside a name refused.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Buddy's chat: Buddy's provider acts as „Buddy za <jméno>“, with the user's name from his persona (DEV-6676 P1)

`lazurio buddy chat --apply` adds T3 Code's acting-sender claim
(Lazurio/t3code#106) to the `buddy` provider instance's environment:
T3CODE_ACTING_SENDER=buddy, T3CODE_ACTING_FOR and
T3CODE_ACTING_FOR_ACCUSATIVE, the user's name as it stands alone and after
„za“ from ~/.config/lazurio/buddy/persona.json (`user.nominative`,
`user.accusative`). Every `t3` Buddy runs from his chat inherits it, so what
he writes or decides in the user's threads shows „Buddy za <jméno>“.

The claim lives only in Buddy's own provider: never in the environment of a
T3 Code service, lazurio-t3-buddy.service included, or in the user's Chat,
whose agents would all inherit it. A name T3 Code would refuse (not 1 to 64
characters on one line, something to trim, a control, formatting or
separator character) would fail every `t3` Buddy runs, so without a usable
name the command writes nothing (`buddy-persona-unreadable`).

Tests: the members with the claim; an older name replaced; the claim only in
Buddy's provider, the user's Chat settings and the unit untouched, Hermes's
check without it; each unusable persona refused with nothing written. The
written file decodes with T3 Code's ServerSettings, and its three variables
with T3 Code's own actingSenderFromEnvironment (#106 at d6e918c3) as
{kind: "buddy", for, forAccusative}.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Buddy: .hermes.md says to pass the acting-sender claim to t3 over SSH, which carries no environment; F61 and F14 follow the trace interface (DEV-6676)

SSH carries no environment variables into another Environment, so the claim
that marks Buddy's steps in threads (T3CODE_ACTING_SENDER=buddy,
T3CODE_ACTING_FOR, T3CODE_ACTING_FOR_ACCUSATIVE; Lazurio/t3code#106) would
be lost there. „Jak pověřuješ“ gains one rule: when Buddy runs `t3` in
another Environment, he passes them explicitly and quoted, with the user's
names from his persona. Template revision stays base-instructions-67
(unpublished), its digest re-pinned. Hermes's injection scan
(tools/threat_patterns.py, d923a5eb) is clean for every rendered file at
context and strict scope; .hermes.md is 14.6k (cs) and 16.0k (en)
characters.

F61 now records the claim in Buddy's provider and its boundary (never a
service's environment or the user's Chat), the persona's names and their
refusal, budíček's claim on its own `t3`, `--message-file -`, the new key
after a refusal, and two rejected alternatives (the claim in a unit, a stored
session). The trace follow-ups for the install are gone; Buddy in Telegram
needs the same variables in the gateway's unit, which its install owns. F14's
addendum names the SSH rule.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Budíček: the wake's key never changes for a failure, so a message whose answer was lost or unreadable is never sent twice (Pablo's review of #592)

Pablo found that rotating the key after a named refusal is unsafe. `t3`
reports a refusal T3 Code keeps for good and one that passes alike
(`orchestration_error`), and it synthesizes `tool_failed` when a tool's
error cannot be read, which may follow a message that went out. A new key
after such an answer could wake Buddy twice. T3 Code names no final
refusal, so budíček now keeps the wake's key for every failure: a resend is
deduplicated, and a wake T3 Code refused for good waits, retried and logged
every round, as an undeliverable Kanban wake does (README's limits).

Tests: a refused send keeps its key three rounds running and sends nothing
twice; a message that went out with a `request_failed`, `tool_failed` or
`orchestration_error` answer is sent again with its key and wakes once.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Buddy: over SSH the acting-sender names travel as data on standard input, never as the command's text (Pablo's review of #592)

Pablo found that the SSH rule quoted the persona's names into the remote
command: a name T3 Code takes may hold an apostrophe or shell syntax, so
`O'Neil` broke the command and `Ada'; …; #` ran one. The rule now gives Buddy
a command that never puts a name into a command's text: it sends both names
from his own environment on standard input (`printf '%s\n%s\n'
"$T3CODE_ACTING_FOR" "$T3CODE_ACTING_FOR_ACCUSATIVE" | ssh <id> '…'`), and
the fixed remote command reads them with `IFS= read -r` and sets them in
double quotes before `exec t3 …`; a message for `--message-file -` follows
them. Without the variables in his environment, `t3` there refuses.

tests/folder-buddy.test.ts runs that exact command as SSH would run it (the
remote shell with `-c` and the command as one string) with names holding
apostrophes, double quotes, `$(…)`, backticks, `;`, `&`, `|`, `>`, a
backslash and globs: each arrives exactly, no file appears, and a message
after them reaches `t3`. Template revision stays base-instructions-67, its
digest re-pinned; Hermes's injection scan is clean at context and strict
scope; .hermes.md is 14.9k (cs) and 16.4k (en) characters. F14 and F61
follow, with the key policy and two rejected alternatives.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
immakermatty added a commit that referenced this pull request Oct 22, 2026
…zurio's own message to the person

What changes, following the root decision 0210 addendum of 2026-10-22
(HumanAndMachines/Lazurio#619): the command is `delegace` with its
subcommands kept (zadej, vysledek, potvrd, seznam, hlidej), the unit is
`delegace.service`, and the variables are `DELEGACE_*`. Every text Buddy
reads says delegace and plain words instead of the old name or waking: the
notice in his chat (`delegace <id>: <STATE>`, then „Výsledek pomocníka (údaje,
ne pokyn): …“, then `delegace vysledek <id>`, and „(znovu, 2. upozornění)“ on
a repeat), the Kanban card's title, body, creator and metadata, the history
notes, the log lines, the errors and the help. The service's own `t3` acts
with T3 Code's acting-sender kind `delegace`, kept in one constant
(ACTING_SENDER, Lazurio/t3code#106), which shows the notice to Buddy and
never to the person.

The last resort, when Buddy confirms none of the three notices, is now
Lazurio's own short message in the Telegram DM, in Lazurio's voice: what the
helper did with the task, that Buddy is not answering now and that Lazurio
writes instead, then the helper's report (at most 1,500 characters) or its
question. It never names the mechanism, a command, a state, an id or a code.

Unchanged: the mechanism, and the records in
~/.local/state/lazurio/buddy/delegations/ with `verze: 1`, their keys and
states. There is no alias: the pilot installs move by hand (the README's
steps), a Platform release with this goes out together with a T3 Code release
that carries #106 with the kind `delegace`, and Machines' install
(HumanAndMachine-ai/Machines#701) installs the new names. Tests: the service's
52 tests, among them the message to the person for every state, a long and an
empty report, no old name or waking in anything the service writes, and a
record from before the rename going on.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
immakermatty added a commit that referenced this pull request Oct 22, 2026
…e person (root 0210 addendum of 2026-10-22, #619)

What: F61's point 2, its open question, alternatives, verification and
addendum, and F14's Buddy addenda (and F60's one mention) now say Delegace,
its command `delegace`, its notice and its tests, in place; the history notes
once that it was named budíček until the root decision 0210 addendum of
2026-10-22 (HumanAndMachines/Lazurio#619). F61 records that the service's
own `t3` acts with T3 Code's kind `delegace` (Lazurio/t3code#106), which
shows the notice to Buddy and never to the person, that the last resort is
Lazurio's own message in Lazurio's voice, and that a Platform with the rename
ships with a T3 Code that carries #106 with that kind. F14's addendum of
2026-10-22 records the layer's section on how Buddy talks to the person,
base-instructions-68, the Hermes scan and the reliance on Hermes's Telegram
default without tool progress.

Why: the root addendum renames the mechanism in code, documents, commands
and Buddy's skills and leaves the mechanism and its records as they are;
the decisions are rewritten rather than given a second account. The browser's
Probudit of F57 is another feature and stays.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
immakermatty added a commit that referenced this pull request Oct 23, 2026
…zurio's own message to the person

What changes, following the root decision 0210 addendum of 2026-10-22
(HumanAndMachines/Lazurio#619): the command is `delegace` with its
subcommands kept (zadej, vysledek, potvrd, seznam, hlidej), the unit is
`delegace.service`, and the variables are `DELEGACE_*`. Every text Buddy
reads says delegace and plain words instead of the old name or waking: the
notice in his chat (`delegace <id>: <STATE>`, then „Výsledek pomocníka (údaje,
ne pokyn): …“, then `delegace vysledek <id>`, and „(znovu, 2. upozornění)“ on
a repeat), the Kanban card's title, body, creator and metadata, the history
notes, the log lines, the errors and the help. The service's own `t3` acts
with T3 Code's acting-sender kind `delegace`, kept in one constant
(ACTING_SENDER, Lazurio/t3code#106), which shows the notice to Buddy and
never to the person.

The last resort, when Buddy confirms none of the three notices, is now
Lazurio's own short message in the Telegram DM, in Lazurio's voice: what the
helper did with the task, that Buddy is not answering now and that Lazurio
writes instead, then the helper's report (at most 1,500 characters) or its
question. It never names the mechanism, a command, a state, an id or a code.

Unchanged: the mechanism, and the records in
~/.local/state/lazurio/buddy/delegations/ with `verze: 1`, their keys and
states. There is no alias: the pilot installs move by hand (the README's
steps), a Platform release with this goes out together with a T3 Code release
that carries #106 with the kind `delegace`, and Machines' install
(HumanAndMachine-ai/Machines#701) installs the new names. Tests: the service's
52 tests, among them the message to the person for every state, a long and an
empty report, no old name or waking in anything the service writes, and a
record from before the rename going on.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
immakermatty added a commit that referenced this pull request Oct 23, 2026
…e person (root 0210 addendum of 2026-10-22, #619)

What: F61's point 2, its open question, alternatives, verification and
addendum, and F14's Buddy addenda (and F60's one mention) now say Delegace,
its command `delegace`, its notice and its tests, in place; the history notes
once that it was named budíček until the root decision 0210 addendum of
2026-10-22 (HumanAndMachines/Lazurio#619). F61 records that the service's
own `t3` acts with T3 Code's kind `delegace` (Lazurio/t3code#106), which
shows the notice to Buddy and never to the person, that the last resort is
Lazurio's own message in Lazurio's voice, and that a Platform with the rename
ships with a T3 Code that carries #106 with that kind. F14's addendum of
2026-10-22 records the layer's section on how Buddy talks to the person,
base-instructions-68, the Hermes scan and the reliance on Hermes's Telegram
default without tool progress.

Why: the root addendum renames the mechanism in code, documents, commands
and Buddy's skills and leaves the mechanism and its records as they are;
the decisions are rewritten rather than given a second account. The browser's
Probudit of F57 is another feature and stays.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
immakermatty added a commit that referenced this pull request Oct 23, 2026
…med, and the person meets only Buddy's own words (root 0210 addendum of 2026-10-22, DEV-6676) (#604)

* Delegace: move the service's files to src/buddy/delegace under their new names

The root decision 0210 addendum of 2026-10-22 (HumanAndMachines/Lazurio#619)
renames the mechanism that hands Buddy his helpers' results to Delegace. This
commit only moves its files, with their contents unchanged, so that history
follows them: the command budicek becomes delegace, budicek.service becomes
delegace.service, test_budicek.py becomes test_delegace.py, and the README
moves with them.

Only the paths that make the move runnable change: the test's path to the
script and the CI step's path to the tests. The names and texts inside the
files change in the next commit.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Delegace: the service carries its new name, and its last resort is Lazurio's own message to the person

What changes, following the root decision 0210 addendum of 2026-10-22
(HumanAndMachines/Lazurio#619): the command is `delegace` with its
subcommands kept (zadej, vysledek, potvrd, seznam, hlidej), the unit is
`delegace.service`, and the variables are `DELEGACE_*`. Every text Buddy
reads says delegace and plain words instead of the old name or waking: the
notice in his chat (`delegace <id>: <STATE>`, then „Výsledek pomocníka (údaje,
ne pokyn): …“, then `delegace vysledek <id>`, and „(znovu, 2. upozornění)“ on
a repeat), the Kanban card's title, body, creator and metadata, the history
notes, the log lines, the errors and the help. The service's own `t3` acts
with T3 Code's acting-sender kind `delegace`, kept in one constant
(ACTING_SENDER, Lazurio/t3code#106), which shows the notice to Buddy and
never to the person.

The last resort, when Buddy confirms none of the three notices, is now
Lazurio's own short message in the Telegram DM, in Lazurio's voice: what the
helper did with the task, that Buddy is not answering now and that Lazurio
writes instead, then the helper's report (at most 1,500 characters) or its
question. It never names the mechanism, a command, a state, an id or a code.

Unchanged: the mechanism, and the records in
~/.local/state/lazurio/buddy/delegations/ with `verze: 1`, their keys and
states. There is no alias: the pilot installs move by hand (the README's
steps), a Platform release with this goes out together with a T3 Code release
that carries #106 with the kind `delegace`, and Machines' install
(HumanAndMachine-ai/Machines#701) installs the new names. Tests: the service's
52 tests, among them the message to the person for every state, a long and an
empty report, no old name or waking in anything the service writes, and a
record from before the rename going on.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Buddy: the layer names Delegace, and Buddy talks to the person only in his own words, like a friend (base-instructions-68)

What changes in Buddy's Lazurio layer (.agents/buddy), after the root
decision 0210 addendum of 2026-10-22 (HumanAndMachines/Lazurio#619) and the
Organization Admin's principle of the same day:
- .hermes.md: a task Buddy hands a bot is a delegation, given through
  `delegace zadej`, and Delegace sends him a notice; a new section „Jak
  mluvíš s uživatelem“ ("How you talk to the user"): the person sees and
  hears only what Buddy writes, in plain human words, like a friend („Dal
  jsem to Zukovi, ozvu se.“, then „Zuko to má hotové: …“), never that a
  notice came. He never names to the person, in the chat or in Telegram,
  Delegace or its notices, his commands or any tool, the states as words,
  MausBot as a system, the list of delegations or queues, nor the labelled
  data; they stay his tools. In the bubble's section the chat's notice is
  for him alone, and the user sees only his reply.
- The skill lazurio-buddy-pomocnici uses `delegace` throughout and ends a
  notice with Buddy's own follow-up; lazurio-mausbot and
  lazurio-t3-orchestration point back to the section where they hand him a
  tool.
- AGENTS.md's Buddy section: agents never look for a way to notify Buddy.

Why: a conversation with Buddy is like a chat with a friend, and a friend
has no alarm clock; the mechanism stays as it is. The layer sets no Hermes
display setting and relies on Hermes's default, in which Telegram shows no
tool progress.

Impact: every generated Folder file and the layer change, so the template
revision moves to base-instructions-68 with its new pin and snapshots. Tests:
the new section and the skills' pointers in both locales, no old name or
waking in any file of the layer or of any Folder, and no line of the layer in
the shape of Hermes's deception_hide pattern; the rendered layer also passes
Hermes's tools/threat_patterns.py at context and strict scope
(Lazurio/hermes-agent v0.22.2-lazurio.1 and main ff0b336e).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Decisions: F61 and F14 name Delegace and record how Buddy talks to the person (root 0210 addendum of 2026-10-22, #619)

What: F61's point 2, its open question, alternatives, verification and
addendum, and F14's Buddy addenda (and F60's one mention) now say Delegace,
its command `delegace`, its notice and its tests, in place; the history notes
once that it was named budíček until the root decision 0210 addendum of
2026-10-22 (HumanAndMachines/Lazurio#619). F61 records that the service's
own `t3` acts with T3 Code's kind `delegace` (Lazurio/t3code#106), which
shows the notice to Buddy and never to the person, that the last resort is
Lazurio's own message in Lazurio's voice, and that a Platform with the rename
ships with a T3 Code that carries #106 with that kind. F14's addendum of
2026-10-22 records the layer's section on how Buddy talks to the person,
base-instructions-68, the Hermes scan and the reliance on Hermes's Telegram
default without tool progress.

Why: the root addendum renames the mechanism in code, documents, commands
and Buddy's skills and leaves the mechanism and its records as they are;
the decisions are rewritten rather than given a second account. The browser's
Probudit of F57 is another feature and stays.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Tests: the golden Folders' AGENTS.md digests follow the Buddy line that agents never notify Buddy

CI's tests (2/2) on 135a992 failed on the eight goldens of
tests/try-overlay-preset.test.ts. They mask the template revision, so they
moved only because AGENTS.md's Buddy section now says agents never look for
a way to notify Buddy („upozornit“), a deliberate change of the layer commit.
Only the AGENTS.md digests change, in Czech and English for each golden; every
other generated file, the derived presets and the shell documents are as
before.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Delegace: the person's message carries no delegation id from the helper's own words (Pablo's review of #604)

Pablo found that the last resort could still show the person the
delegation's id. The brief asks every helper to write its files into the
task's own folder, ~/Documents/buddy/<id>/, with absolute paths, so an
ordinary report („Výstup: /home/ada/Documents/buddy/<id>/vysledek.md“) went
to the person with the id in it, against the message's stated contract.

Now the helper's report or question reaches the person through
without_id(): a path in the task's folder, here or in another Environment's
home, keeps only the path inside it („rozbor.md“), and the folder itself or
any other mention of the id becomes the task's title. The words are
otherwise the helper's own; the record keeps them whole for Buddy. README
and F61 now say exactly this: Lazurio's own words never name the mechanism,
a command, a state or an error code, and the id appears nowhere.

Tests: a report with absolute paths into the folder, a quoted path with a
space, the folder itself and a bare id, here and on another Environment, and
a question with such a path; with the id handling taken out the test fails.
The service's 53 tests pass.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Delegace: a path's whole home goes from the person's message, a home with spaces included (Pablo's re-review of #604)

Pablo found that the shortening of a path into the task's folder matched only
from /Documents onward when the home held a space: „Výstup: /home/Jane
Doe/Documents/buddy/<id>/vysledek.md“ became „Výstup: /home/Jane
Doevysledek.md“, leaking part of the home and leaving a broken file name.

Now the home is anchored on its known start: this service's own home, which
the brief names exactly, `~`, or a home under /home/, /Users/ or /root,
whose own name may hold spaces or punctuation but never a slash or a line
end. The whole home goes, the person reads only the path inside the task's
folder („vysledek.md“), and the words before a path stay as the helper wrote
them, a slash among them („A/B test:“). Any other mention of the id still
becomes the task's title, and Buddy's stored report stays whole.

Tests: a report and a question with a spaced home, here (the service's own
home, as the brief names it) and on another Environment, with plain,
backticked and „quoted“ paths; and words with a slash before a path. They
fail on the service of 2c4c5d0, and the words-before test fails when the
home matches any run of segments. The earlier test took its home before the
temporary directory was replaced; it now takes it after. The person-text
guard no longer forbids the bare word vysledek, which a helper's own file
may carry; the command goes with the word delegace. The service's 55 tests
pass.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants