Skip to content
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions adoption/new-wsl/claude-user-instructions.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ Decide by evidence and research convergence: a choice stands when current primar
- Resolve supported findings before claiming completion. Distinguish measured results, simulations and untested boundaries; unchanged upstream tests, local integration checks, synthetic fixtures and actual provider execution are different evidence classes. New machines collect their own evidence; historical receipts do not certify the new host.
- Settle a discoverable harness capability by step 2 before asking the user; compare community alternatives against demonstrated gaps, retain source pins and reasons, and run the selected native path through returned results. Dated exclusions are not current availability evidence. Research only the relevant layers.
- Carry the user's authorized work through implementation, relevant verification and a concise handoff. Use a short plan for bounded work; do not add intake, repeated approvals, diagnostic campaigns or restarts without a concrete need. Preserve existing edits, native accounts, model choices and project scope.
- When you tell the user a time, give it first in the host's local time zone (read it with `timedatectl` or `date`), with UTC beside it, for example "4:00 PM EDT (20:00Z)"; keep UTC in ledger rows, receipts, evidence and commits.
- Use the project's canonical instructions for memory scope, tests and domain rules, and keep durable memory and indexes scoped to that project.

## Token practice (base layer)
Expand Down
1 change: 1 addition & 0 deletions adoption/new-wsl/codex-user-instructions.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ Long commands: set `yield_time_ms` 30000; while a `session_id` returns, poll `wr
Web research: if the stack installs GPT Researcher, run `bash ~/code/native-agent-stack/tools/research/gpt_researcher.sh "<short current-month query>"` as a long command (stops at 1,500 s); use short, unseeded current-month queries; reports are leads: re-read facts in primary sources.
Message Claude Code in one long command: set `msg` via a quoted heredoc (`msg=$(cat <<'MSG'`, text, `MSG`, `)` each on its own line), then `printf '%s\n\nreply: codex queue --thread %s\n' "$msg" "$CODEX_THREAD_ID" | claude -p -n "codex-$(printf '%.8s' "$CODEX_THREAD_ID")" --permission-mode bypassPermissions --max-turns 3 --output-format stream-json --verbose "Send the text on stdin, complete and verbatim, to the session named <name> with exactly one SendMessage call, then stop."`.
Codex receives queued messages only between turns; idle delay is up to ~20 s.
When you tell the user a time, give it first in the host's local time zone (read it with `timedatectl` or `date`), with UTC beside it, for example "4:00 PM EDT (20:00Z)"; keep UTC in ledger rows, receipts, evidence and commits.

<!-- native-agent-stack:rtk-upstream rtk-ai/rtk v0.51.0 hooks/rtk-awareness-full.md, verbatim -->
# RTK
Expand Down
32 changes: 28 additions & 4 deletions adoption/platforms/linux-wsl2-new-distro.md
Original file line number Diff line number Diff line change
Expand Up @@ -449,7 +449,7 @@ systemctl show getty@tty1.service -p Result -p NRestarts
Pro for WSL writes it), that line lists its top-level keys: record them, and stop if `users:` or `write_files:` is among
them. cloud-init 26.1 merges `agent.yaml` over the user-data one top-level key at a time, and an agent key replaces the
user-data key entirely (`DataSourceWSL.py:317-336`, called at `:490`). Either key would replace the user or the
`[user] default` of W3.
`[time]` and `[user] default` of W3.
- The `.wslconfig` line only reads: it prints the file's section headers and its `instanceIdleTimeout` and
`vmIdleTimeout` lines, or nothing when the file or the keys are absent. Record both values in the receipt's
`idle_keys`; a missing key has its default. `instanceIdleTimeout` (under `[general]`, default 15000 ms, `-1` turns it
Expand Down Expand Up @@ -560,6 +560,8 @@ wsl.exe -d '<Name>' -u root --exec cat /var/lib/cloud/data/result.json
wsl.exe -d '<Name>' -u root --exec cat /var/lib/cloud/data/status.json
wsl.exe -d '<Name>' -u root --exec cloud-init schema --system
wsl.exe -d '<Name>' -u root --exec cat /etc/wsl.conf
wsl.exe -d '<Name>' --exec timedatectl show -p Timezone --value
tzutil /g
wsl.exe -d '<Name>' -u root --exec ls -l /etc/cloud/cloud-init.disabled
wsl.exe -d '<Name>' -u root --exec sudo -l -U '<WSL_USER>'
wsl.exe --list --verbose
Expand Down Expand Up @@ -620,7 +622,26 @@ Proof (path A, cloud-init provisioned the instance):
schema exits 1 (`:1493-1498`). The `schema` subcommand never reads the marker (`cloudinit/cmd/main.py:1240-1241`,
`:1286-1293`). The 26.04.1 rehearsal returned `Valid schema user-data` after the marker on both host releases;
each run must repeat that observation. Record the output (`schema_system`).
- `/etc/wsl.conf` holds `[boot]`, `systemd=true`, `[user]` and `default=<WSL_USER>`, each once.
- `/etc/wsl.conf` holds `[boot]`, `systemd=true`, `[time]`, `useWindowsTimezone=true`, `[user]` and
`default=<WSL_USER>`, each once. The `[time]` key restates WSL's default and records the intent
([Microsoft wsl-config, "Time settings"](https://learn.microsoft.com/en-us/windows/wsl/wsl-config#time-settings), read
2026-10-05: MicrosoftDocs/WSL `7ea1c6f9`, `WSL/wsl-config.md:152-158`, `useWindowsTimezone`, default `true`); W6
writes the same key on path B. This read-back proves the file's text at this boot only; nothing reads it later.
- `timedatectl show -p Timezone --value` prints the IANA zone that CLDR's `windowsZones` mapping gives for the Windows
zone that `tzutil /g` prints and the Windows region: the first zone of the region's row, else the `001` row, for
Comment thread
seathatflowsinourveins marked this conversation as resolved.
Resolved
example `America/New_York` for `Eastern Standard Time` in the US (unicode-org/cldr `release-48-2`, `11299982`,
`common/supplemental/windowsZones.xml:130` and `:133`). `tzutil /g` displays the current time zone ID
([tzutil](https://learn.microsoft.com/en-us/windows-server/administration/windows-commands/tzutil), read 2026-10-05:
MicrosoftDocs/windowsserverdocs `48fd0532`, `tzutil.md:18` and `:25`). WSL maps the zone with the ICU that Windows
ships and, while `useWindowsTimezone` was true when the instance started, links `/etc/localtime` to it at each
instance start and again in a running instance when Windows' time zone changes (microsoft/WSL `91f161fa`, tag 3.0.1:
`src/windows/common/helpers.cpp:358-413`, `src/linux/init/timezone.cpp:22-110`; the decision record cites both
paths). Record both outputs. On either path, a mismatch is recorded with both outputs and stops the run for review,
without the failed-proof recovery below: WSL leaves `/etc/localtime` unchanged when the Windows-to-IANA mapping is
empty (`Windows to Linux timezone mapping was not possible.`, `timezone.cpp:54-58`) or the image lacks the zone's
file (`... not found. Is the tzdata package installed?`, `:66-70`). The remedy is to check the Windows region and
zone against that mapping and the image's `tzdata` (`/usr/share/zoneinfo/<zone>`); unregistering the distribution
would not change either.
- The marker file exists, and `sudo -l` lists `(ALL) NOPASSWD: ALL`.
- The starred line of `--list --verbose` is still W1's (`default_distribution_after`).

Expand Down Expand Up @@ -670,8 +691,10 @@ proof: the mask did not take effect before the unit started. Record all of it, w
kernel from W1 and the image revision from W2, in the receipt's `paired_isolation`: one object for the workstation and
one for `<Name>`, each with `uid`, `system_state`, `failed_units`, `user_manager` and `cgroup_namespace`.

When any W5 proof fails, or the user-session warning appears, stop the run and never stop or restart a unit in either
distribution. Terminate only the new distribution, export its failed state, and unregister only that name. Do not
The time-zone pair is the one exception, on path A and in path B's repeat: a mismatch is recorded and stops the run for
review, as its proof above says, and the recovery below does not run for it. When any W5 proof fails, or the
user-session warning appears, stop the run and never stop or restart a unit in either distribution. Terminate only the
new distribution, export its failed state, and unregister only that name. Do not
take path B for any such failure. Record its cause (`cgroup`, `tty` or a short text); this recovery block serves every
failed W5 proof:

Expand Down Expand Up @@ -778,6 +801,7 @@ printf '%s ALL=(ALL) NOPASSWD:ALL\n' '<WSL_USER>' > /etc/sudoers.d/90-wsl-defaul
chmod 0440 /etc/sudoers.d/90-wsl-default-user
visudo -cf /etc/sudoers.d/90-wsl-default-user
grep -q '^\[user\]' /etc/wsl.conf || printf '\n[user]\ndefault=%s\n' '<WSL_USER>' >> /etc/wsl.conf
grep -q '^\[time\]' /etc/wsl.conf || printf '\n[time]\nuseWindowsTimezone=true\n' >> /etc/wsl.conf
Comment thread
seathatflowsinourveins marked this conversation as resolved.
Resolved
touch /etc/cloud/cloud-init.disabled
```

Expand Down
1 change: 1 addition & 0 deletions adoption/templates/codex.AGENTS.template.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ Long commands: set `yield_time_ms` 30000; while a `session_id` returns, poll `wr
Web research: if the stack installs GPT Researcher, run `bash ~/code/native-agent-stack/tools/research/gpt_researcher.sh "<short current-month query>"` as a long command (stops at 1,500 s); use short, unseeded current-month queries; reports are leads: re-read facts in primary sources.
Message Claude Code in one long command: set `msg` via a quoted heredoc (`msg=$(cat <<'MSG'`, text, `MSG`, `)` each on its own line), then `printf '%s\n\nreply: codex queue --thread %s\n' "$msg" "$CODEX_THREAD_ID" | claude -p -n "codex-$(printf '%.8s' "$CODEX_THREAD_ID")" --permission-mode bypassPermissions --max-turns 3 --output-format stream-json --verbose "Send the text on stdin, complete and verbatim, to the session named <name> with exactly one SendMessage call, then stop."`.
Codex receives queued messages only between turns; idle delay is up to ~20 s.
When you tell the user a time, give it first in the host's local time zone (read it with `timedatectl` or `date`), with UTC beside it, for example "4:00 PM EDT (20:00Z)"; keep UTC in ledger rows, receipts, evidence and commits.
Comment thread
seathatflowsinourveins marked this conversation as resolved.
Resolved

<!-- native-agent-stack:rtk-upstream rtk-ai/rtk v0.51.0 hooks/rtk-awareness-full.md, verbatim -->
<!-- native-agent-stack:include-rtk-awareness-full -->
Expand Down
6 changes: 6 additions & 0 deletions adoption/templates/wsl/cloud-init.user-data.template
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@
# Keys follow Canonical's "Automatic setup of Ubuntu on WSL with cloud-init" example and the cloud-init WSL datasource
# "Default user" example. The groups are the ones the image's wsl-setup gives a user it creates interactively. uid 1000
# matches defaultUid in the image's /etc/wsl-distribution.conf. The password stays locked; sudo needs none.
# [time] useWindowsTimezone=true restates WSL's default (Microsoft wsl-config, "Time settings", read 2026-10-05:
# MicrosoftDocs/WSL@7ea1c6f9 WSL/wsl-config.md:152-158; default true). It records the intent, and W5 reads it back:
# docs/decisions/2026-10-05-user-facing-local-time.md.
# P2 checks the workstation schema; W5 must validate the selected image's own schema. Full new-host acceptance is owed.
users:
- name: ${WSL_USER}
Expand All @@ -21,6 +24,9 @@ write_files:
- path: /etc/wsl.conf
append: true
content: |
[time]
useWindowsTimezone=true

[user]
default=${WSL_USER}

Expand Down
2 changes: 1 addition & 1 deletion adoption/templates/wsl/first-boot-checklist.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ readlink /proc/self/ns/cgroup
- [ ] **W2** Explicit `<RELEASE>` is one of the two controlled arms; download URL, filename and catalog entry match that release. The actual whole-image, signed Canonical publication and pinned DistributionInfo.json SHA-256 all equal that release's exact hash above; actual file size recorded (run 2 observed 418,495,746 bytes for 26.04.1); no `throw`.
- [ ] **W3** `%USERPROFILE%\.cloud-init\<Name>.user-data` exists, starts with `#cloud-config`, names `<WSL_USER>` twice and contains no `${`; its SHA-256 equals P2's.
- [ ] **W4** The selected `ubuntu-<RELEASE>-wsl-amd64.wsl` installs with exit 0; `Distribution successfully installed`; `<Name>` is `Stopped` at version 2; the starred line is unchanged.
- [ ] **W5** First launch exit 0, without the prompt marker; `wsl: Failed to start the systemd user session` stops even with exit 0; `id -un` is `<WSL_USER>` and `id -u` is `1000`; getty `is-enabled` prints `masked` (normal exit 1), and `show` prints `LoadState=masked`, `ActiveState=inactive`, `NRestarts=0`, recorded as `getty_mask`; selected-image `cloud-init --version` recorded; `cloud-init status --long` prints `status: disabled` with `boot_status_code: disabled-by-marker-file` (with the template's `bootcmd` it exits 2 on one expected recoverable error, `Failed to wait for network`, because WSL masks `systemd-networkd-wait-online.service`; any other recoverable error is recorded and reviewed); `/var/lib/cloud/data/result.json` names `DataSourceWSL` with `"errors": []`; `/var/lib/cloud/data/status.json` shows the four stages finished without errors; `cloud-init schema --system` prints `Valid schema user-data` and exits 0; `/etc/wsl.conf` names the user once; `/etc/cloud/cloud-init.disabled` exists; sudo is NOPASSWD; the starred line is unchanged. After the first launch, while both distributions run and before F1, the already-running distribution reads a system unit active in both: its `cgroup.procs` has local process ids and no `0` entry, and the new distribution's `user@<uid>.service` is active. An empty or unreadable file is inconclusive and stops. The paired block below records each of the five commands on each side in its own receipt entry with its own exit, in `paired_isolation`: the same uid, both user managers `active`, the new distribution `running` with no failed unit or `degraded` with `systemd-binfmt.service` as its only failed unit (message proved at F1), two `cgroup:[...]` values that differ from each other and are not `cgroup:[4026531835]`, and all five workstation values equal to its W1 baseline. A getty failed in the new distribution or newly failed in the workstation fails the proof. Any failed W5 proof terminates only the new distribution, never stops or restarts a unit in either, exports `<Name>-w5-failed.tar` with the exit guard and its cause (`cgroup`, `tty` or a short text) in `w5_failure_export`, unregisters and checks surviving `WSLInterop` and a Windows executable, with R1's records and stop for review. Do not take path B for any such failure. On both paths, record P3's baseline before the import and `second_count` after the first launch. An increase confined to the window in which the new disk is attached, before cloud-init starts, is recorded with the new lines and does not stop the run. Any storage error after that window, or any provisioning step that fails with a storage cause, stops the run. An unknown attachment window stops for review; storage failures retain microsoft/WSL#41482 and their own cause.
- [ ] **W5** First launch exit 0, without the prompt marker; `wsl: Failed to start the systemd user session` stops even with exit 0; `id -un` is `<WSL_USER>` and `id -u` is `1000`; getty `is-enabled` prints `masked` (normal exit 1), and `show` prints `LoadState=masked`, `ActiveState=inactive`, `NRestarts=0`, recorded as `getty_mask`; selected-image `cloud-init --version` recorded; `cloud-init status --long` prints `status: disabled` with `boot_status_code: disabled-by-marker-file` (with the template's `bootcmd` it exits 2 on one expected recoverable error, `Failed to wait for network`, because WSL masks `systemd-networkd-wait-online.service`; any other recoverable error is recorded and reviewed); `/var/lib/cloud/data/result.json` names `DataSourceWSL` with `"errors": []`; `/var/lib/cloud/data/status.json` shows the four stages finished without errors; `cloud-init schema --system` prints `Valid schema user-data` and exits 0; `/etc/wsl.conf` names the user once and sets `useWindowsTimezone=true` under `[time]`; `timedatectl show -p Timezone --value` prints the IANA zone that CLDR's `windowsZones` mapping gives for the zone `tzutil /g` prints and the Windows region, both recorded; a mismatch, on either path, is recorded and stops for review without the export and unregister: check the Windows region and zone against that mapping and the image's `tzdata`; `/etc/cloud/cloud-init.disabled` exists; sudo is NOPASSWD; the starred line is unchanged. After the first launch, while both distributions run and before F1, the already-running distribution reads a system unit active in both: its `cgroup.procs` has local process ids and no `0` entry, and the new distribution's `user@<uid>.service` is active. An empty or unreadable file is inconclusive and stops. The paired block below records each of the five commands on each side in its own receipt entry with its own exit, in `paired_isolation`: the same uid, both user managers `active`, the new distribution `running` with no failed unit or `degraded` with `systemd-binfmt.service` as its only failed unit (message proved at F1), two `cgroup:[...]` values that differ from each other and are not `cgroup:[4026531835]`, and all five workstation values equal to its W1 baseline. A getty failed in the new distribution or newly failed in the workstation fails the proof. Any other failed W5 proof terminates only the new distribution, never stops or restarts a unit in either, exports `<Name>-w5-failed.tar` with the exit guard and its cause (`cgroup`, `tty` or a short text) in `w5_failure_export`, unregisters and checks surviving `WSLInterop` and a Windows executable, with R1's records and stop for review. Do not take path B for any such failure. On both paths, record P3's baseline before the import and `second_count` after the first launch. An increase confined to the window in which the new disk is attached, before cloud-init starts, is recorded with the new lines and does not stop the run. Any storage error after that window, or any provisioning step that fails with a storage cause, stops the run. An unknown attachment window stops for review; storage failures retain microsoft/WSL#41482 and their own cause.

```sh
id -u
Expand Down
18 changes: 18 additions & 0 deletions adoption/templates/wsl/stage1-receipt.example.json
Original file line number Diff line number Diff line change
Expand Up @@ -766,6 +766,18 @@
"exit": "<exit code>",
"output_excerpt": "<sanitized output>"
},
{
"step": "W5",
"cmd": "wsl.exe -d '<Name>' --exec timedatectl show -p Timezone --value",
"exit": "<recorded exit code>",
"output_excerpt": "<W5: the IANA zone; it must be the CLDR windowsZones mapping of the tzutil /g zone for the Windows region, for example America/New_York>"
},
{
"step": "W5",
"cmd": "tzutil /g",
"exit": "<recorded exit code>",
"output_excerpt": "<W5: the Windows time zone ID, for example Eastern Standard Time>"
},
{
"step": "W5",
"cmd": "wsl.exe -d '<Name>' -u root --exec ls -l /etc/cloud/cloud-init.disabled",
Expand Down Expand Up @@ -1060,6 +1072,12 @@
"exit": "<path B only: exit code; null on path A>",
"output_excerpt": "<path B only: sanitized output; null on path A>"
},
{
"step": "W6",
"cmd": "grep -q '^\\[time\\]' /etc/wsl.conf || printf '\\n[time]\\nuseWindowsTimezone=true\\n' >> /etc/wsl.conf",
"exit": "<path B only: exit code; null on path A>",
"output_excerpt": "<path B only: sanitized output; null on path A>"
},
{
"step": "W6",
"cmd": "touch /etc/cloud/cloud-init.disabled",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,11 +85,11 @@
"sha256": "ff94e93390875a4c6d2baa352fa7075e66acc7a966b33f1ef62338fb9988b7f3"
},
{
"path": "adoption/templates/wsl/cloud-init.user-data.template",
"path": "evidence/artifacts/user-facing-local-time-20261005/frozen-inputs/cloud-init.user-data.template.txt",
"sha256": "08e6a3f6b078dfa54d78297596d54729d10528d57147b9b9eae063c37160eeb9"
},
{
"path": "docs/decisions/2026-10-01-new-wsl-distro-recipe.md",
"path": "evidence/artifacts/user-facing-local-time-20261005/frozen-inputs/2026-10-01-new-wsl-distro-recipe.md.txt",
"sha256": "ec03a494aa4d80ac004f74710250bf1ac7cf18e0506758d97a1cf98a0cee42a3"
}
],
Expand All @@ -101,11 +101,11 @@
],
"evaluation": [
{
"path": "adoption/templates/wsl/first-boot-checklist.md",
"path": "evidence/artifacts/user-facing-local-time-20261005/frozen-inputs/first-boot-checklist.md.txt",
"sha256": "1a06df0e6d50b07b439317a61a450e450127052589f63254e769d99166e3603b"
},
{
"path": "adoption/templates/wsl/stage1-receipt.example.json",
"path": "evidence/artifacts/user-facing-local-time-20261005/frozen-inputs/stage1-receipt.example.json.txt",
"sha256": "7c0811c460fe8732f413b954cd7ddadb5cc41a5300f8686b5b83aefcd80a971a"
},
{
Expand Down
Loading
Loading