Commit Graph
4015 Commits
Author SHA1 Message Date
Codeman maintainer 0a0ebfd274 docs: plugin users and the skill default, and what a local session keeps
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>
2026-11-08 08:47:31 +01:00
Codeman maintainer 938c213552 fix(skill): sendmark also ends on a settled answer file
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>
2026-11-08 08:47:26 +01:00
Codeman maintainer 3d61402250 docs(agent-skill): record the reference-folder symlink refusal and the live CLI checks
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>
2026-11-08 08:37:00 +01:00
Codeman maintainer cd2265f8d0 docs(agent-skill): name GitHub Copilot among the CLIs that get no skill copy
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>
2026-11-08 08:35:38 +01:00
Codeman maintainer df98912596 test: keep session creates out of the machine's real /tmp
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>
2026-11-08 08:35:04 +01:00
Codeman maintainer ddcdd5d974 fix(agent-skill): refuse a symlinked reference folder inside the skill copy
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>
2026-11-08 08:33:02 +01:00
Codeman maintainer 5a9de1bc4c fix(skill): name sendmark's workers by class, not a partial mode list
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>
2026-11-08 08:24:14 +01:00
Codeman maintainer 0aa34da80f feat(settings): the codeman agent skill is on by default
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>
2026-11-08 08:13:51 +01:00
Codeman maintainer 83576153d0 ci(local-model): name the digest contract and ask for measured rows first
A row can pin its build only as `digest`, the value /api/tags reports
after the pull, and LocalModelEntrySchema must gain that optional field
before the weekly check can compare it. The script header and the docs
now say so, so the field cannot arrive under another name and be ignored.

Until it exists, the report's digest table names the build a Mac pulls
for each row and asks for the rows with measured figures first: their
memory figures describe one build, and without a digest a rebuild of
about the same size goes unnoticed. A switch between the mlx and the gguf
build is still caught by the size check (2% or more apart).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-08 07:54:21 +01:00
Codeman maintainer d12bef0833 ci(local-model): check the model catalogue and the runtime pin every week
scripts/check-local-model-catalog.mjs reads every catalogue tag the way
Ollama 0.40.15 on Apple silicon reads it: it asks for the manifest list,
takes the mlx build when the tag offers one (else llamacpp, else ggml),
and compares that build's pull total (layers plus config) with the row's
`bytes`. It also reports a tag that is gone, a build whose `requires` is
newer than the pinned runtime, a pinned digest that moved, a newer Ollama
release, and a pinned ollama-darwin.tgz that is gone or changed. It never
requests a layer, bounds every request, retries nothing and validates
everything that reaches the report. Exit 0 clean, 1 drift, 2 failed.

The plain Docker manifest of a list tag is the llamacpp build, not what a
Mac pulls. Read the right way, the first run finds two rows sized from the
wrong build: qwen3.5:9b (a Mac downloads 7,639,229,431 bytes, +16.6%) and
qwen3.8:27b (18,174,721,847, +2.4%).

.github/workflows/local-model-catalog.yml runs it Mondays at 06:00 UTC
and on dispatch. The check job installs with --ignore-scripts and holds a
read-only token; a separate job with issues: write and no checkout opens
or updates the one "Local model catalogue: weekly check" issue on drift,
comments on it on a clean week when it is open, and is skipped when the
check failed. Actions are pinned by commit.

docs/local-models.md gains "Keeping the catalogue current".

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-08 07:50:27 +01:00
Codeman maintainer 91ca7e54de docs(local-model): cloud plus local, through the codeman skill
docs/local-models.md says how a Claude Code session drives the model on
this Mac through the skill (local_model, spawn_worker local, sendmark)
and what stays true: the skill never installs a model or answers a
confirmation, one request at a time, and Stop and Remove wait for the
workers it opened.

The README gets the local model as a feature with that pairing, and an
example prompt in the skill's table; the wiki's skill page gets the same
row and a short paragraph.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-08 07:49:22 +01:00
Codeman maintainer 28e8029ce5 docs(skill): Claude in the cloud, a local model on this Mac
SKILL.md gets a subsection after the DeepSeek Harness workers: why to hand
work to the model on this Mac (bulk work with no per-token bill, files
that stay on the machine, a second opinion, a worker that needs no
network), the copy-paste block (local_model, spawn_worker local, sendmark,
delete_session), and the limits as the code has them: a person installs
the model, one request at a time, slower than the cloud, markers not
hooks, a spawn can start a runtime the person stopped, admin only and
experimental.

The description now names the local model, so "use the local model"
reaches the skill. Section 2 gains a row, the hook-less row points at
sendmark, and reference/verbs.md gets 5.16 with every local_model reason,
the spawn steps and the sendmark exit codes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-08 07:48:32 +01:00
Codeman maintainer b913092be3 feat(skill): spawn and drive a worker on the local model
The codeman skill's preamble learns the model Codeman installs on this Mac:

- local_model asks GET /api/v1/local-model and prints one JSON line: the
  installed model, the coding agent that runs it and its endpoint, or the
  reason there is none (not a Mac, nothing installed, an unfinished
  install, a blocked install, admin only, a server without the routes).
  Exit 0 only when a worker can start now or after a runtime start.
- spawn_worker <name> local (and name:local in spawn_workers) starts a
  stopped runtime the way the window's Start button does, quick-starts the
  installed agent with customModel, and waits for its composer (OpenCode's
  bar, the claude path for a claude agent, LOCAL_READY_MARK otherwise). A
  confirmation question from quick-start fails the spawn with empty stdout;
  nothing is ever confirmed on the person's behalf.
- sendmark <sid> <prompt> drives any agent worker without an end-of-turn
  signal: the exactly-once input body, a split marker through wait-output,
  then the answer read back from a file the worker wrote in its folder
  (regular files only, 256 KB at most), with one exit code per outcome.

The preamble stamp moves to 1.50.0 so every cached copy is rewritten.
The tests run the real preamble against a stubbed server.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-08 07:48:08 +01:00
Codeman maintainer 9c64fc128d docs(agent-skill): say the skill is on by default and stays out of git
Every place that called the Codeman Agent Skill setting off by default now
says it is on by default since 1.50.0, where to turn it off, and that turning
it off still removes no copy already written (`codeman skill uninstall --case
<name>` does). The README, the wiki's Codeman Skill page and the FAQ say an
agent inside Codeman usually has the skill without an install step, and that
the copy ignores itself in git.

Also written down: an install whose App Settings were saved on an earlier
version stored the old default and stays off until switched on; with the
Claude Code plugin installed, Claude Code lists the skill twice (both work);
and, in the invariants, the self-ignoring `.gitignore` rules and the
measurement that Claude Code 2.1.319 never runs `git check-ignore` on a skill
folder. The agent control plan keeps its original default-off decision and
gains a dated note for the flip.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-08 07:45:20 +01:00
Codeman maintainer b3f0ba9e29 feat(agent-skill): turn the Codeman agent skill on by default
An absent `agentSkillEnabled` now means on, on the server
(`getAgentSkillEnabled()` reads `!== false`, like `workspaceHooksEnabled`)
and on the page (the App Settings switch loads `!== false`, so a Save of any
other setting no longer writes the old default back). Only an explicit false
turns it off. A partial settings PUT that omits the key leaves it as stored,
since the route merges the request into the file.

The switch's help text says it is on by default, that the copy stays out of
git, and that turning it off removes no copy already written. The shared
route-test mock now defaults to on too, so route tests see what a user sees.

Tests: quick-start against a real server (absent key injects, a partial PUT
keeps it on, an explicit false stays off through a later partial PUT), the
real openAppSettings/saveAppSettings in JSDOM (absent shows on, explicit false
shows off, a Save on a never-touched install sends true and passes the
schema), and the plain create route at the mock's default.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-08 07:42:56 +01:00
Codeman maintainer ba9d311cb7 feat(agent-skill): make the injected skill copy ignore itself in git
Every Codeman-managed copy of the agent skill (`.claude/skills/codeman/`,
`.agents/skills/codeman/`, and the user-level copy) now carries a `.gitignore`
of `*`, written once with O_EXCL before any skill file, the way the prompt
uploads folder does. A user's repository no longer lists the copy as
untracked, and Codeman never touches the repository's own ignore files.

A file already at that name is never overwritten, a copy injected before this
gains the file on its next install (reported as refreshed), and uninstall
removes it only when it is the last thing left and holds exactly `*`, so a
user's extra files in the folder stay ignored. Claude Code 2.1.319 runs
`git check-ignore` only on directories at or above `.claude/skills`, never on
a skill folder, so the skill still loads.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-08 07:35:03 +01:00
Codeman maintainer 569eed2b3e docs(wiki): name the app's Add a Coding Agent menu item as the app shows it
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-08 07:32:44 +01:00
Codeman maintainer ac59cfa9ca docs(desktop): an agent can be added from the app later, under its real menu name
The desktop README's Known limits still said an agent is added by hand after the install, and the wiki gave the menu item a shorter name than the one the app shows.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-08 07:32:23 +01:00
Codeman maintainer 89d18eb9a2 Merge chore/remove-ralph-start-button: the wiki sentence that goes with it 2026-11-08 07:00:16 +01:00
Codeman maintainer b497748e31 docs(wiki): Ralph starts from Session Options only
The welcome screen's "Start Ralph Loop" button is gone (chore/remove-ralph-start-button), and it was the wizard's only entry point, so the page no longer offers the wizard as a second way in.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-08 07:00:16 +01:00
Codeman maintainer 34a7812008 Merge docs/mac-app-download: scope the Apple logo blink to the MacBook Pros that have it
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-08 05:03:15 +01:00
Codeman maintainer 0c63f76d31 Merge ci/macos-app-release: a rebuild by hand takes only a Codeman release tag on master
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-08 05:03:15 +01:00
Codeman maintainer 8f5d2d9bb0 docs: scope the Apple logo blink to the MacBook Pros that have it
"A MacBook Pro whose Apple logo lights up" also describes the 2013 to 2015
Retina MacBook Pros, whose lid logo glows from the display backlight and which
run macOS 11 or 12, both of which the app supports. The View menu's Blink
Apple Logo exists only where CoreBrightness answers for the lid logo
(logo::available() in packages/desktop/src/logo.rs), which is a MacBook Pro
with a PROLED XDR display. The README, its Chinese mirror and the wiki now use
packages/desktop/README.md's wording, so the wiki's "the menu only exists on
such a Mac" holds.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-08 05:03:09 +01:00
Codeman maintainer ea23445ad7 ci(desktop): a rebuild by hand takes only a Codeman release tag on master
A dispatch with -f tag=<any tag> built that tag, and sign then ran the tag's
sign-macos.sh with the Developer ID key unlocked and the notary login in its
environment. Nothing checked the tag: xterm-zerolag-input@0.1.7 would have put
Codeman.dmg on that package's release, and a tag on a commit that never
reached master would have run unreviewed scripts with the secrets.

build and sign now each check their own checkout before anything else runs:
the tag must read codeman@x.y.z (or aicodeman@x.y.z, which a failed rename
leaves) and GitHub's compare of master with the checked-out commit must say
behind or identical. The check is inline, since a script from the checkout
would be the tag's own code. Release's own call (a push, not a dispatch) and
the branch dry run are unchanged.

The header says why a master-only Environment would not close this path, and
release.yml's macos-app job now says that any permission a called job asks
for must be granted there too, or Release fails at startup.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-08 05:02:45 +01:00
Codeman maintainer 5c61fc1ea8 docs(wiki): Ralph starts from Session Options only
The welcome screen's "Start Ralph Loop" button is gone (chore/remove-ralph-start-button), and it was the wizard's only entry point, so the page no longer offers the wizard as a second way in.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-08 04:09:00 +01:00
Codeman maintainer 028bd87494 fix(files): no outside worktree for an adopted session, and say what the routes re-check (#780)
outsideWorktreeOptions() now returns undefined for an adopted session as it does for a remote or Docker one: session.remote and session.docker are undefined on an adopted session, so it needs its own test. An adopted pane gets no paneCwd today (paneExitApplies), so nothing changes in practice; the rule stays true if that ever changes.

The live-worktree.ts @fileoverview said the routes re-check only the realpath of an outside worktree. They also judge the attachment guard rules again on every request (isOutsideWorktreeRootRefused() through withGuardedOutsideWorktree()), which is what makes a confinement or blocked-tree change apply at once.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-08 04:08:43 +01:00
Codeman maintainer 2e61ac9534 test(worktrees): keep the system gitconfig out of the code under test (#776)
The two stubs from #776 cover the global ignore file and the global config. A core.excludesFile in the system gitconfig still reached the code under test and failed the same test (reproduced with GIT_CONFIG_SYSTEM pointing at one). GIT_CONFIG_NOSYSTEM closes that, as test/git-hooks.test.ts already does for its code under test.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-08 04:07:39 +01:00
Codeman maintainer e19b2c3a54 Merge docs/mac-app-download: link the Codeman app for Mac from the README and the wiki
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-08 04:07:07 +01:00
Codeman maintainer 31ce0c88cd Merge ci/macos-app-release: build, sign, notarize and attach Codeman.dmg on every release
release.yml and docs/releasing.md take the branch's text, which is master's text plus the macOS app additions (its first commit copied both files from master).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-08 04:07:05 +01:00
Codeman maintainer e8a63ede00 Merge feat/local-model-recommendation: recommend and install a local coding model on this Mac (experimental)
Conflicts resolved as on test/desktop-macbook: config/test-suites.ts keeps both browser tests (desktop-connect-page and local-model-ui), and the CLAUDE.md state-files line keeps #778's cli-installed entry with the local model's local-model.json and local-model/ entries.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-08 04:06:46 +01:00
Codeman maintainer 2522ac1727 Merge chore/remove-ralph-start-button: remove the "Start Ralph Loop" button from the start screen
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-08 04:06:01 +01:00
Codeman maintainer 2f9cc7aabc Merge #780 feat(files): follow the agent into a worktree outside the session folder
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-08 04:05:56 +01:00
Codeman maintainer 10db8a4bd9 Merge #776 test: keep two tests independent of the host's locale and git ignore file
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-08 04:05:53 +01:00
Codeman maintainer e6c79c8e8c Merge #779 fix(macos): never run Apple's placeholder git, which opens the developer tools window
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-08 04:05:49 +01:00
Codeman maintainer 98c4a3d386 Merge #778 fix(cli): a running server notices a CLI the installer just added
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-08 04:05:41 +01:00
Codeman maintainer 4b349b57f6 Merge #773 feat(desktop): install Codeman from the app, with no Terminal and no password
Conflicts resolved as on test/desktop-macbook: install.sh usage() lists CODEMAN_NO_ADMIN=1 or 0 and #773's CODEMAN_AI_CLI and CODEMAN_PROGRESS=1; probe.rs keeps #781's agent() with TIMEOUT, MAX_BODY and probe_within all pub; the desktop README keeps both known-limits entries.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-08 04:05:38 +01:00
Codeman maintainer a7343fe087 Merge #781 feat(desktop): blink the lid Apple logo with what the agents are doing
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-08 04:05:02 +01:00
Codeman maintainer 49e1dda23b Merge #782 fix(approvals): the list leaves a dialog too new to judge
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-08 04:04:59 +01:00
Codeman maintainer a192fb7253 Merge #763 feat(desktop): native macOS app that runs, installs or connects to Codeman
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-08 04:04:57 +01:00
Codeman maintainer d5273347c3 ci(desktop): build, sign, notarize and attach Codeman.dmg on every release
Every Codeman release now carries the Mac app as Codeman.dmg and
Codeman.dmg.sha256, under a name that never changes, so
https://github.com/Ark0N/Codeman/releases/latest/download/Codeman.dmg always
serves the newest app.

.github/workflows/desktop-dmg.yml (workflow_call from Release with
tag codeman@<version>; workflow_dispatch with an optional tag) has three jobs,
so no job that holds a secret runs code from a crate:
- build (macos-26, contents: read, no secret, no cache) runs cargo test --locked
  and bundle-macos.sh --universal ad hoc, with CODEMAN_DESKTOP_INSTALLER_URL,
  CODEMAN_DESKTOP_INSTALL_BRANCH and SIGN_IDENTITY unset, checks both slices,
  the signature and that no test installer URL or branch is baked in, and
  uploads the app as a ditto zip.
- sign (macos-26, contents: read) refuses an artifact with an entry outside
  Codeman.app, a ".." or a symlink, imports MACOS_CERT_P12 into a keychain under
  RUNNER_TEMP with a random password, picks the one Developer ID Application
  identity by its hash and checks it belongs to APPLE_TEAM_ID, runs sign-macos.sh
  with the Apple ID login and uploads the signed pair as the codeman-dmg
  artifact. Its last step deletes the keychain and the decoded .p12 whatever
  happened before.
- attach (ubuntu, contents: write, no secret) runs only with a tag, on master
  (Release itself, or a rebuild started there) and in Ark0N/Codeman; it uploads
  the pair with --clobber and checks that the release's download link, and the
  Latest one when this release holds Latest, serve those bytes.
A run without a tag is the dry run: everything but attach.

release.yml reads the Codeman version from changesets' publishedPackages
(published alone is also true for an xterm-zerolag-input-only release) and runs
the macOS app job only for a Codeman release, passing it the five secrets by
name, never secrets: inherit. A new step puts Latest back on the newest
codeman@ release after every publish, so a release that moved only
xterm-zerolag-input no longer takes the badge and breaks the stable link. Both
new steps sit after the retag and only warn on failure, so npm, the tag and the
MCP publish are never held up by them.

desktop-ci.yml checks pull requests and master pushes that touch
packages/desktop: cargo fmt --check, clippy -D warnings, cargo test --locked and
bash -n under macOS's bash 3.2, on macos-26 with a read-only token. Both
workflows pin Rust 1.99.1, what the macos-26 image and the Mac mini ran on
2026-11-08.

docs/releasing.md: step 6 holds a site change that links the app until the DMG
check passes, step 7 names the new job, and a new section covers the secrets,
the check, a dry run, a rebuild and what to do when notarization fails.

actionlint 1.7.12 (with shellcheck 0.11.0) reports nothing on the three
workflows, and master's test/release-notes.test.ts assertions hold on the new
release.yml.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-08 04:03:25 +01:00
Codeman maintainer 94912241bc feat(desktop): sign-macos.sh signs, notarizes and staples the app and its DMG
The release DMG is signed with the owner's Developer ID and notarized, so a
downloaded copy opens after macOS's usual confirmation instead of stopping at
Gatekeeper. The work is a script of its own, so CI and a Mac run it the same way:

  SIGN_IDENTITY=... NOTARY_PROFILE=<profile> \
    packages/desktop/scripts/sign-macos.sh <Codeman.app> <out-dir>

It re-signs the app with the hardened runtime, a secure timestamp and
macos/entitlements.plist, checks the signature is a Developer ID one with the
runtime flag, has notarytool notarize it and staples the ticket, builds the DMG
around the stapled app, signs it, notarizes and staples it too, and has spctl
assess both. Codeman.dmg and Codeman.dmg.sha256 reach <out-dir> only after every
check passed; a failed run removes an older pair there rather than leave one to
upload by mistake. A submission Apple does not accept stops the script with its
id and Apple's log. The notary login is either a notarytool keychain profile
(NOTARY_PROFILE, NOTARY_KEYCHAIN) or APPLE_ID, APPLE_APP_PASSWORD and
APPLE_TEAM_ID; `sign-macos.sh --check` tests that without doing anything.

The DMG layout (the app next to an /Applications link, UDZO, volume "Codeman")
moves to make-dmg.sh, which both scripts call, and gains a retry: hosted macOS
runners now and then fail hdiutil create with "Resource busy". bundle-macos.sh
keeps its SIGN_IDENTITY path as it was; its new --notarize checks the
environment before building, then hands the app to sign-macos.sh.
packages/desktop/README.md says the release DMG is notarized and how to do
the same by hand, and drops the CI build and notarization from its ideas list.

All three scripts are bash 3.2 clean, and shellcheck reports nothing. With the
macOS tools stubbed, sign-macos.sh was run under bash 3.2 through a full
signing, a notarization rejected for the app and for the DMG, two hdiutil
failures then a pass, three failures, a relative out-dir and every missing
setting.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-08 03:57:29 +01:00
Codeman maintainer 1e262b04d1 chore(release): take release.yml and docs/releasing.md from master as they are
This branch starts from feat/desktop-app (#763), which predates master's MCP
registry job and the release-notes body in release.yml and their pages in
docs/releasing.md. Both files are master's text verbatim here, so the Mac app
commit after this one changes them by additions only, and a rebase onto master
drops this commit as empty.

release.yml now names .github/workflows/publish-mcp.yml and
scripts/generate-release-notes.mjs, which exist on master but not on this
branch. The Release workflow runs only on pushes to master, so that matters
nowhere else.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-08 03:57:11 +01:00
Codeman maintainer baf9dfa2eb docs: link the Codeman app for Mac from the README and the wiki
The 1.50.0 release attaches Codeman.dmg to every release, so
https://github.com/Ark0N/Codeman/releases/latest/download/Codeman.dmg
always serves the newest app. This puts that link where a Mac user
looks first:

- README.md: one line under the install one-liner, and a short
  "On a Mac: the Codeman app" section in Quick Start, after Docker
  Compose. What the app does, the download, universal (Apple Silicon
  and Intel), macOS 11.3, the WebKit of Safari 16.4 for Codeman's page,
  macOS 15 (or a tmux already there) for the install from the app, and
  how to update it.
- README.zh-CN.md: the same, translated.
- docs/wiki/Installation.md: a matching section with a First launch
  list (the one "downloaded from the internet" question, the Local
  Network question on macOS 15) and the limits that matter on day one.
  Its anchors, #on-a-mac-the-codeman-app and #first-launch, are what
  the website links for first-launch help. Route A points to it.

The limits are copied from packages/desktop/README.md. The app is
signed with a Developer ID and notarized, so no Gatekeeper workaround
and no per-update Keychain prompt is described.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-08 03:44:00 +01:00
Codeman maintainer 7edf1a1c27 feat(desktop): a blink style for each state of the agents
The logo said one thing: agents are working. It now has a style of its own
for each state the tabs show: at work, finished and waiting for you (yellow),
and stopped on a permission or a question (red), set under View > Blink Apple
Logo. The most urgent state with a style wins, red then yellow then work, and
a state set to Off falls through to the next instead of silencing the logo.

Red and yellow come from `GET /api/approvals`, the list the page rebuilds
those tabs from after a reload, read natively for the reason the session list
is: WebKit stalls a hidden page's stream. An idle item stops counting once it
is acknowledged, so the logo stops when the tab's colour goes. The request is
skipped while neither alert has a style, a 404 from an older server reads as
no alerts, and a request that fails keeps the last answer. A dialog on screen
costs the server one tmux capture per poll.

Alarm is new: three sharp flashes and a short rest. It stays under the limit
of three flashes in any second, so its urgency comes from its shape.

A style saved by the earlier version stays as the one for work, and yellow
and red start as Wink and Alarm, since whoever chose one asked for a logo that
talks. `SETTLE` goes from 2 s to 3 s, the time the server takes to judge a new
dialog, so a prompt answered before its hook landed never flashes red.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-07 16:26:16 +01:00
Codeman maintainer 324aa75896 fix(approvals): the list leaves a dialog too new to judge
`GET /api/approvals` re-reads the pane of every pending dialog and resolves
one whose frame shows no dialog, either because its options vanished or
because the frame shows a turn running. `notePrompt` deliberately waits 3 s
before making that same judgement, since the Notification hook can land
before Ink paints the dialog and the working line is still on screen then.
The list did not wait. That rarely mattered while it ran once per page load,
but a client that polls it would resolve a live prompt as answered in the
terminal, clearing the red alert on every device and the push Approve button
with it. `sweepForList` skips a dialog younger than the delay.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-07 16:21:37 +01:00
Codeman maintainer cd4cee15a7 feat(desktop): blink the lid Apple logo while agents work
On a MacBook Pro with a PROLED XDR display, the lit Apple logo on the lid
can blink while agents work and stop when they finish, so a run can be
read from across the room. View > Blink Apple Logo While Agents Work
picks a style (Calm, Slow, Wink, Heartbeat, Fast). It is off by default,
and the menu exists only on a Mac that has the logo.

Apple documents one control for the logo, `sudo defaults write
com.apple.CoreBrightness LEBacklightMode -int 0`. The same setting is a
property of BrightnessSystemClient in the private CoreBrightness
framework, which a process of the logged-in user can set with no
administrator, so nothing here needs a helper or a password.

The setting is system-wide and survives a reboot, and the release profile
has panic = "abort", so the work runs in a child process (this binary
with --logo-blink) tied to the app by a pipe. When the pipe closes,
however the app ended, the child restores the logo and exits. A marker
file covers power loss and a SIGKILL of the child itself.

The child asks api/sessions itself: WebKit stalls the event stream of a
hidden page, which lost whole turns and ran a blink 39 s past the end.
It sends the session cookie of its first answer with every poll, because
a good password without a cookie creates a login session each time and
Codeman evicts the oldest of 100.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-07 05:06:39 +01:00
Codeman maintainer 59af305e84 feat(desktop): find the Codeman servers running on this Mac and offer to connect
When a Codeman server of this user ran at an address the app could not open
as its default one, the This Mac tab only named host and port and sent the
user to Another machine to type the address again. A second instance beside
the one that answers (a beta, a `codeman web --port 4000` in a terminal) was
not shown at all.

The look at this Mac now works out an address for every listening socket of
this user's Codeman servers (`found_addresses`, pure): 127.0.0.1 for a bind
to loopback or to every interface, `[::1]` when that is the only loopback
socket, the address itself for a bind to one; `https` and the base path come
from `--https` and `--base-url` on the command line. A server at the default
address with no `--base-url` of its own keeps the default URL, since
install.sh's launchd job has the base path in its environment, where `ps`
does not show it. The default address comes first, then the others by port.

Each address other than the default one is asked once, all at the same time,
with no login. The default probe's answer is reused for its own row. When
nothing answers at the default address, the first found server that answers
is still what Open is for, so each gets the probe's usual 5 s; next to a
Codeman that answers they are only listed and get 2 s. `LocalStatus.found`
replaces `elsewhere`.

The tab lists them: "Codeman is already running on this Mac." with a row
each when none answers at the default address, and "Also running on this
Mac" under Open otherwise. A row has the address, the version and Connect,
or the reason the app cannot open it. Connect fills the address in and runs
the page's one connect(), so the app checks it, uses its saved login and
remembers it like an address typed under Another machine. Nothing connects
by itself, and a refused connect from a row never arms the reopen that Open
has for a starting server.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-11-07 04:27:16 +01:00
Codeman maintainer be8fc2980a style(local-model): white for the feature, built like the primary launcher
The violet button was the one thing on the start screen outside the app's
blue, and it carried white text and a see-through disc where its neighbour
has dark ink and a solid disc. It is now white with dark ink and a solid
disc, the same on the Install button, and the chooser's selected row, tile
and model bar follow. Light skins turn it over to dark, since a white button
vanishes on a pale page. The context takes the app's blue.

The tokens are named for what they mean now (--lm-brand, --lm-context).

Brings test/local-model-ui.browser.test.ts up to the redesign it had fallen
behind: it is outside the gate, so the button's 46 px, the 12 px bar and the
memory panel's edges had gone unnoticed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-07 04:23:02 +01:00
Codeman maintainer aa76b1b304 style(local-model): rose for the brief peaks in the memory map
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-07 03:44:19 +01:00
Codeman maintainer 6b1664abae docs(local-model): the memory map in the frontend rules
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-07 03:22:25 +01:00