_onWebSpeechEnd counted every run that ended without a result toward the
two-retry cap, however long the run lasted. Under 30 s or Manual, each
no-speech window of the engine is one silent run, so the third ended the
recording at about 18 s of silence, before the deadline, and Manual
stopped on its own. Both recognition.start() sites now stamp the run start;
an empty run counts toward the cap only when it ended within a second of
starting (a recognizer that cannot listen), and any other run resets it.
The 250 ms backoff is unchanged.
The vm harness in test/voice-silence-timeout.test.ts now passes the test's
Date into the context, whose own Date ignores fake timers.
Also from review: the VoiceInput stubs of the four settings-ui.js tests
carry SILENCE_TIMEOUT_SECONDS; Settings-Reference lists Stop after silence;
the touchscreen Linux fallback leaves out ChromeOS and says a touch Linux
laptop still matches; the dead _webSpeechStream teardown is gone; the two
voice tests use vitest expect instead of node:assert.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The install window polls GET /api/local-model every second. A read of the
state file that was still out while the job wrote its last state and let
go of this.job came back with the old `installing`, and settling that with
no job in the process read it as an interrupted job: `paused` with Resume
for one tick before `failed`. Under CI load this made
test/local-model-install-e2e.test.ts fail on a different failure case per
run (master 86502b69, PR #790).
currentState() now reads again when the job ended during the read. The job
writes before it lets go, so the second read has the final state.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
5.3 MB for the universal app and 3.5 MB for the DMG, measured on the Mac
mini from this branch; the README still had the first build's 4.6 and 3.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
No behavior change: the connect page renders pixel-identical in eight
states (Chromium, before and after), posts the same messages, and passes
its jsdom and browser tests.
- policy.rs: the connect commands' camelCase fields come from serde's
rename_all_fields instead of three per-field renames; parse_ipc's
length and id checks are match guards like its other arms, with the
message cap named (MAX_MESSAGE_LEN); new_window reads its URL through
external_url, which is the same parse-and-http(s) check.
- logo.rs: the stubs for other platforms are one module, and Logo,
Marker and recover are private to the file.
- connect.html: answers() is the one test for a server that answers
(six copies), the running and needs-login rows of This Mac share their
branch, prepareWizard, needsAgent, newWait and openTerminal each
replace two or three copies, a finished install and a finished agent
share their path, host() is displayAddress(), state.clock is in the
state literal, three CSS rules that matched nothing are gone, and the
state comments say what wait and gui hold now.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
No behavior change.
- ProbeOutcome::version replaces two copies of the same match in setup.rs,
and classify_response reads the status JSON with serde_json's indexing
(same answer for every body, a missing key is Null).
- local_server::is_env_name is the one test for a variable name, used by
the login shell's environment and by ~/.codeman/.env.
- setup.rs has basename() for its two command-line scans; the install
scan no longer formats the script prefix once per word.
- agents.rs: refused() names the statuses that end the polling, and
answer() takes the body it already has instead of a closure.
- Small simplifications in gui_install.rs (Run::matches, follow, the
download error text) and a let-else in local_server::launch.
- Docs that no longer matched the code: probe.rs said the probe never runs
in a loop, but the This Mac tab re-asks while it waits for an install
(every 3 s) or for a starting server (every second); local_server.rs
covered only Start; FIND_TIMEOUT and exec named one caller of several.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
No behavior change. What was written out two to four times now has one
name:
- AppWindow::new and AppWindow::hidden_for_download, window_builder,
placed_position (the corner tao places, which the frame save and the
pop-out cascade both read; cfg! instead of two attribute pairs),
file_name_of and UNNAMED_FILE for the download toast.
- page_sender, which in_background, attach_to_run and both install
starts use; plan_message and remote_install_failed for the connect
page's answers; open_external_raw for the two OpenExternal commands;
choosing() for the four phase checks.
- An accepted probe (Ok, or a password to change) runs one set of steps.
- macos::install runs inside build_webview, so no web view can be built
without the dialog and login handlers.
- ProbeDone no longer carries the Authorization header beside the
username and password it is made from; basic_auth makes it.
- Load::ConnectPage loses its manual flag, which was never true there.
- MIN_SIZE reads config's limits, the default username is
setup::DEFAULT_USERNAME, and the repository and wiki addresses live
in menu.rs.
- The module doc names the modules as they are now, and two doc comments
that had slid onto the wrong item are back on theirs.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Pure moves, no function body changed (git diff --color-moved shows it):
- terminal_install.rs: the Terminal and SSH installs (the scripts, the
ssh arguments, open_in_terminal, copy_to_clipboard) and their tests,
out of setup.rs, which keeps one subject: the Codeman on this Mac.
- login.rs: choose_login, update_keychain and their types and tests,
out of main.rs.
- menu.rs: the menu bar, its ids and AppMenu, out of main.rs.
- policy.rs: loaded_on_commit and its test, a pure Phase decision like
the rest of policy.
What changed besides the moves: module paths, pub on the moved items,
imports, the module docs, and the plutil test's temporary folder name,
which no longer draws on the Terminal scripts' counter. main.rs goes from
2312 to 1881 lines and setup.rs from 2160 to 1625.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The feature table no longer says v0.1, a few paragraphs that had grown
past the wrap width are rewrapped, and the Gatekeeper limit now starts
with the signed and notarized release DMG, so the ad hoc steps read as
what they are: for a build of your own.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
ureq and wry already pull in base64 0.23 and dirs 7, so the app's own
base64 0.22 and dirs 6 were compiled beside them. The app now asks for the
versions already in the tree. base64 is declared as ureq declares it,
without the default SIMD engines, so the feature set compiled is the one
ureq had before. dirs 7 resolves config_dir and home_dir on macOS exactly
as 6 did (both go through dirs-sys 0.5).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The "Featured in Awesome AI Agents" badge pointed at a list with far fewer
stars than this repository, so it added nothing. The Download for Mac button
under the tagline is a fifth smaller in both READMEs.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The only DMG link above the fold was a plain link in the sentence under the
install command, easy to read past. Both READMEs now open with a large
"Download for Mac" button right under the tagline, pointing at the latest
release's Codeman.dmg, with one line on what the app is.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The previous commit counted 4 rollback copies of the recurrent state for every GGUF with a
prediction layer, the runtime's default `draft_num_predict`. A tag can set its own in its
params layer, and the runtime then passes that as `--spec-draft-n-max`, which is what
`need_n_rs_seq()` turns into rollback copies. Read on 2026-11-08:
- qwen3.6:35b-a3b-mtp-q4_k_m: draft_num_predict 2, so 2 copies (was counted as 4).
- qwen3.8:27b-mtp-q4_k_m: draft_num_predict 4.
- qwen3.8:27b-q8_0: none in its params, so the runtime's 4.
The 35B-A3B GGUF row's overhead drops by 132 MB: 0.971 instead of 0.976 on a 36 GB M3 Pro or
M3 Max, the same pick. test/local-model-catalog.test.ts now carries the drafted tokens per row
instead of a yes/no prediction layer.
Also states what was verified about llama.cpp's checkpoint default: 8 from b6800 to b8200,
32 from b8250 together with a checkpoint every 8,192 prompt tokens (common/common.h at those
tags), in place of an inferred reason. Checked in the b12111 source as well: the draft context
of a Qwen-family MTP model caches the prediction block alone (`mtp_on_hybrid_qwen`, layers at
or above n_layer()), and the main context leaves it out, so the row counts that layer once.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The weekly check's report and docs ask for an optional `digest` on each catalogue row, but the
catalogue keeps no digest on purpose: test/local-model-catalog.test.ts ("holds no download
data") refuses a `sha256` anywhere in it. Say so where the digest contract is described, so a
maintainer reads it as a decision for the catalogue, not a quick schema change.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The catalogue that names each row's runner (feat/local-model-catalog-v2: `runner` is `mlx` or
`llamacpp`, and a row's memory figures follow that runner's rule) needs the weekly check to
notice when a tag starts serving a Mac another runner: a tag that gains an mlx child, or a
list that loses it. The size check usually catches that, but not when the two builds come out
about the same size, and the figures are wrong either way.
classifyModel() now raises a `runner` finding when the row names a runner and the build a Mac
selects runs on another one. catalogueRunner() maps the registry's names into the catalogue's:
`mlx` stays `mlx`; `llamacpp`, and `ggml` (what Ollama calls a GGUF manifest that names no
runner), are `llamacpp`, because Ollama 0.40.15 serves every GGUF build through llama-server.
A catalogue without the field (the one on this branch today) is never held to a runner.
Run live on 2026-11-08 against the v2 catalogue's eight rows: exit 0, every runner matches.
Tests: the mapping, the finding (both directions, ggml, an unknown runner, a row without the
field), the report text, and runCheck against the fake registry with a plain GGUF manifest.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The llama.cpp memory rule of the catalogue left out two allocations that the llama.cpp the
runtime bundles (b12111, the runtime's LLAMA_CPP_VERSION) makes for every GGUF row:
- Context checkpoints. For a model whose state cannot be rolled back (the recurrent state of
the Qwen-family rows, the sliding window of North Mini Code), llama-server keeps host copies
of that state, two or three per request, up to 32 per slot by default
(tools/server/server-context.cpp create_checkpoint). For the 27B that is 32 x 157 MB = 5 GB,
none of which was counted. The runtime now sets LLAMA_ARG_CTX_CHECKPOINTS=8 (read by
llama-server from its environment like LLAMA_ARG_CACHE_RAM; 8 was llama.cpp's own default
before it went to 32), and every llamacpp row counts 8 copies of its state.
- Multi-token prediction. The two -mtp tags and qwen3.8:27b-q8_0 carry a prediction layer
(nextn_predict_layers 1, read from the first bytes of each GGUF; the 9B tags and North Mini
Code have none). The runtime then always passes --spec-type draft-mtp --spec-draft-n-max 4,
so llama.cpp keeps 4 rollback copies of the recurrent state (need_n_rs_seq(),
llama-memory-recurrent.cpp) and the prediction layer's cache in the draft context's cache
type, f16 by default. The rows counted one state and that layer at q8_0.
What moves (test/local-model-recommend.test.ts, "every memory size", re-pinned):
- 16 GB: limited -> none. MiMo 9B at 65,536 tokens needs 10.2 GB, 0.987 of the 10.4 GB
estimate. With the budget the Mac mini measured (10.7 GB after the reserve) it is offered,
0.954, tight; that test is kept. With 4 checkpoints instead of 8 it would be 0.966 on the
estimate: this size sits on the edge, and only a run on such a Mac settles it.
- 18 GB: the same pick, 0.964 instead of 0.928.
- 36 GB: the same picks, 0.966 (27B on M4/M5 Max) and 0.976 (35B-A3B GGUF on M3).
- 48 GB on a Max chip: the 27B at 262,144 tokens is tight (0.853) instead of good.
- 32 GB with a measured budget of 0.74: North Mini Code at 131,072 tokens (was 262,144), the
27B at 65,536 on a Max chip (was 131,072).
- Every MLX row, and everything from 64 GB up, is unchanged.
test/local-model-catalog.test.ts recomputes the new rule from the architecture table and holds
the catalogue to LLAMA_ARG_CTX_CHECKPOINTS. The catalogue header, runtime.ts, the types,
docs/local-models.md, CLAUDE.md and architecture-invariants say the same. Read in the source,
not measured.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The migration's file comment and the invariants said a restored settings.json
stays as restored and that a refused start leaves the migration to the next
start. Both hold, but the first only once the migration has run: after a
first 1.50.0 start that found settings.json unparseable, no marker exists,
so an off saved between the fix and the next start is switched on with the
rest. That is the same "cannot tell a chosen off from the old default" trade
the release note already states, in a narrower window. Both texts now say
so. Comment and docs only.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The JSDoc on `agentSkillEnabled` in SettingsUpdateSchema said the skill is
injected into `<case>/.claude/skills/` on Claude session create and is
"SYNCED, default OFF ... so it is opt-in". Since this branch it is on when
absent, goes into whichever directory the session's CLI scans for skills,
and a false stored by 1.49.0 or earlier is switched on once at the first
1.50.0 start. Comment only.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The Q8 27B row counts a prediction layer its GGUF may or may not carry
(not checked, careful side), and the macOS notice on the runtime's page is
about Laguna XS 2.1; Laguna S 2.1 is set aside for its open runtime issues.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The 48 GB row now says the test was a short task and that MLX may keep up
to 8 GiB more in a long session, which brings the pair to the edge of the
budget. The check after the download says what it proves for each runner,
from the runtime's source: for a GGUF build both of its figures are the
buffers llama-server reports allocating, so the check covers the whole
load whatever the cache type; for an MLX build only the weights. And the
docs say where a new row's architecture goes.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The migration's file comment said test/agent-skill-setting-ui.test.ts proves
both shapes. It pins the shipped one (a stored true wins on a device holding the
old false); the deleted-key shape was measured with the same harness and is not
kept as a test.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The new GGUF rows carry lowercase quantization tags (`-q4_k_m`); pin that
the launch path's model id test (`cliAcceptsCustomModelId()`) accepts every
stock id for every harness the catalogue offers, so a row the chooser shows
can always be started.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
docs/local-models.md gains "Which model fits which Mac": the answer of the
stock catalogue for every memory size from 8 to 512 GB, why the chip
changes it at 36 to 96 GB, and why nothing is offered below 65,536 tokens.
"How much memory a model needs" explains the two runners (llama.cpp
allocates its K/V cache at load, MLX grows it and keeps up to 8 GiB of
prefix snapshots), the three runtime settings the llama.cpp rows assume,
and per row where its memory and speed figures come from. The check after
the download now says that for an MLX build it proves only the weights,
and "What to know" says most figures are calculated, not measured.
CLAUDE.md: every row names its runner and carries its own figures, and
the llama.cpp rows and runtimeEnv() change together.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The catalogue had seven Qwen-family rows that all carried the memory
figures measured on one model (Qwen3.6 35B-A3B on the MLX runner), so a
9B or a dense 27B was judged with figures that do not describe it, two
rows had the wrong Mac download size, and every Mac below 32 GB got
"none".
Now eight rows, each with the runner a Mac really uses for its tag (a new
`runner` field: `mlx` or `llamacpp`) and memory figures of its own:
- the 35B-A3B MLX row keeps its measured figures and the tested pair;
- every llama.cpp row is computed from its model's config.json: a q8_0
K/V cache for the whole context (what the runtime now sets), its
recurrent or sliding-window state, 1.0 GB of runner and the 1 GiB host
prompt cache;
- the one other MLX row (Ornith 1.5 122B) is computed the same way,
scaled by what the measured row showed, plus the runner's 8 GiB of
prefix snapshots.
Sizes are the registry's Mac pull totals (2026-11-08, lowercase ids
verified there). What each memory size gets: 8 GB none; 16 to 32 GB a 9B
(limited); 36 GB Qwen3.8 27B or the 35B-A3B as GGUF; 48 GB the tested
pair (or the 27B on a Max chip); 64 and 96 GB the 27B or the 35B-A3B;
128 to 512 GB Ornith 1.5 122B. Nothing but the one row was measured.
The catalogue test recomputes every computed figure from a table of
architectures and lets two rows share figures only when they share the
architecture and the runner. The rule tests of recommend() now run on a
frozen copy of the 2026-11-06 catalogue, so a weekly catalogue update
changes only the per-memory table and the real-Mac tests.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
runtimeEnv() now also sets OLLAMA_KV_CACHE_TYPE=q8_0, OLLAMA_FLASH_ATTENTION=1
and LLAMA_ARG_CACHE_RAM=1024. Read in the v0.40.15 source of the pinned
runtime: the first becomes --cache-type-k/-v of llama-server (17/32 of the
f16 cache), the second --flash-attn on (a quantized V cache needs it, and
"auto" or "off" would fail such a load), and llama-server inherits the third
from ollama serve's environment, which bounds its host prompt cache to
1 GiB instead of letting it grow by gigabytes in a session. The MLX runner
reads none of them.
The catalogue's llama.cpp rows are computed for these values, so the two
change together. Not yet measured on a Mac.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The changeset, CLAUDE.md, the invariants, the agent control plan, both READMEs
and the wiki's Codeman Skill and Settings Reference pages said an install whose
App Settings were saved on an earlier version stays off until switched on. They
now say the first 1.50.0 start switches a stored off on once, and that turning
it off afterwards sticks. The changeset marks it "Behaviour change:", says the
migration cannot tell a chosen off from the old default, and tells users to
reload a tab left open from before the upgrade before saving App Settings in
it. CLAUDE.md lists the marker file among the data dir's state files, and the
invariants record why it stores true, why the marker is its own file, and
where it runs.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Every App Settings Save up to 1.49.0 wrote `agentSkillEnabled: false`, chosen
or not (the switch loaded an absent key as off and Save sends the whole form),
so the new default never reached an install that had ever saved. On its first
start the server now replaces a stored false with true, once per data dir, and
logs one line when it does. It cannot tell a deliberate off from the old
default; that is accepted and stated in the release notes. An off set after it
ran stays off.
It stores true rather than deleting the key: the page's merge overwrites only
the synced keys the server has, so every device that saved on 1.49 kept its own
false, showed the switch off and wrote false back on its next Save (measured in
the JSDOM harness). True wins on every device, including a browser still on a
cached settings-ui.js. For a server with no key the page now drops the device's
copy as well, so the switch shows the default.
The "done" marker is its own file, `agent-skill-default-migrated.json` in the
data dir: it is not a setting, so GET /api/settings never returns it, no Save
can send it back (the strict schema would refuse it) or drop it (which would
re-arm the migration), and a config-backup restore leaves it alone. It is
checked before anything is read and written only after the settings write
landed. The migration runs in WebServer.start() before the first settings read
and before listen (skipped in test mode, like the other boot-time writes),
writes only through mutateSettingsFile(), drops the 2 s settings cache, and
leaves a settings.json that does not parse alone with no marker, so the next
start after the fix runs it.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The skill-on-by-default change ships in its own pull request with the self-ignoring copy, so this branch keeps the old default and its wording. The local models guide no longer says nothing leaves the machine: the prompts go to the local model, while the coding agent may still check for updates.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This reverts commit 0aa34da8, which made the codeman agent skill default on here as well. That change lives in feat/agent-skill-default-on, together with the self-ignoring copy and the reference-folder symlink check it needs.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
session.test.ts created a session in the fixed `/tmp/test`, so with the agent
skill on by default every `npm test` wrote a skill copy into
`/tmp/test/.claude/skills/codeman/` and left it there. It now uses a temp
folder of its own and removes it afterwards.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The opencode readiness and marker measurements were made on Linux, not
on a Mac, and the docs now say so. A worker whose pane ends after it
wrote its answer file but before the marker matched answers 3 with no
answer: the rc 3 row now says the file may still be in its folder. The
example's input folder is named input, so the prompt reads cleanly.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The Codeman Agent Skill setting is now on by default, and the per-case
copy it writes lists twice next to the Claude Code plugin (codeman and
codeman:codeman), the same as a codeman skill install would. The README
and the wiki now say so and tell plugin users to turn the setting off.
The README's local model bullet said the session "sends nothing off the
machine". The server keeps the runtime on loopback with its cloud
features off, but opencode itself is not configured offline (its model
catalogue and update checks are untouched), so the bullet now says what
the code does: the prompts and files go to a model on this Mac.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Measured on opencode 1.3.0 in a private tmux socket, with a fake
OpenAI-compatible endpoint streaming the reply a character or two at a
time: the marker was on the screen, but the stripped client stream read
D, spinner, O, spinner, N, ... because opencode redraws its spinner
between the streamed pieces, so wait-output never matched it. sendmark
then waited its whole timeout and answered 2 for a reply that had
finished, with the answer file already written (opencode's write tool
wrote it without asking).
The marker wait now runs in rounds of at most 10 s, and between rounds
the answer file is a way out too: a non-empty regular file whose
checksum held still for one round is read, with matched false. The
marker stays the fast path. The answer-file wait after a marker no
longer spins when the exit wait gets no answer, and treats an ended
wait as the worker gone.
The same run measured the readiness mark: with a fresh home and a
custom provider, the first composer bar came with the composer and a
prompt pasted with its Enter at that moment was submitted, so the docs
say so instead of "not measured". The example keeps its input in a
subfolder, apart from the case's CLAUDE.md.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The architecture note now says that install and uninstall refuse a linked
folder inside the copy, why (a cloned repository or a Docker case's
container can plant one), and that the check is not race-proof. It also
records which CLIs were checked live with the copy's ignore file in place:
Claude Code 2.1.319, Codex 0.162, OpenCode 1.3.0 and Grok 1.0.52 all list
the skill; agy, dsh, gemini and omp were not measured.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Copilot's registry entry takes no agent skill, like Pi and a plain shell, but
the changeset, the App Settings help text, the Settings Reference and
CLAUDE.md named only Pi (and the shell). The Agent CLIs wiki page still said
no CLI but Claude gets the bundled skill; every CLI except Pi and Copilot
gets it, in `.agents/skills/`.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Five gate files created sessions with `workingDir: '/tmp'` against a real
server. With the agent skill on by default, every `npm test` then wrote a
skill copy into `/tmp/.claude/skills/codeman/`, outside the per-file temp
HOME, where a Claude Code started in `/tmp` would load it (the workspace
hooks already landed in `/tmp/.claude/settings.local.json` the same way).
Each file now uses a temp folder of its own and removes it afterwards.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Install and uninstall checked only the copy and its parent for symlinks, so a
`reference` folder that is a link carried every write and unlink of
`reference/<name>.md` to wherever it pointed. Measured: install overwrote a
`history.md` outside the workspace and uninstall deleted it. A cloned
repository can commit that link, and a Docker case's container can plant it
in the bind-mounted workspace the host injects into. With the skill on by
default, both now ran without the user asking.
Both paths now return 'symlink' for a linked folder inside the copy, before
the first write or unlink, and the refusal messages say so.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
sendmark's comment and verbs.md 5.5 listed six external modes by name,
and test/agent-skill-mode-lists.test.ts refuses any partial list of them
(the one a ninth CLI would silently miss). Both now say what the class
is: a hook-less claude, a worker on the local model, and every external
agent mode but deepseek.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
agentSkillEnabled now reads an absent key as ON, the way
workspaceHooksEnabled does: only an explicit false turns it off. A new
session therefore finds the codeman skill in its folder without a
setting first, and with it the verbs that hand work to other CLIs and to
the local model on this Mac. Settings shows the switch on for the same
absent key.
The injection itself is unchanged: add-only, marker-owned, never through
a symlink, never for remote sessions or a plain shell. Turning the
setting off still removes nothing already written.
The quick-start test now pins the new default (injected on an absent
key, nothing after an explicit false), and the docs that said "default
off" say when that changed.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>