Skip to content
Apothem

Catatan Perubahan

CHANGELOG Apothem — catatan rilis terkurasi, lalu kategori Keep-a-Changelog untuk rilis berikutnya.

Catatan rilis di bawah ini disuntikkan dari berkas CHANGELOG.md root saat waktu build oleh node site/scripts/update-reference-inventory.mjs; berkas root adalah satu-satunya sumber kebenaran.

Changelog — Apothem

All notable changes to this project are documented in this file.

This changelog follows Keep a Changelog and the project adheres to Semantic Versioning.

Unreleased

Added

  • The Marketplace publish can use Trusted Publishing. With the repository variable VSCE_AUTH=oidc, the VS Code publish job runs vsce publish --oidc, which exchanges the job's GitHub OIDC token for a short-lived Marketplace credential: no stored secret and no Azure setup. The publisher adds one Trusted Publishing policy for this repository, the publish workflow and the release environment. The job first checks that the vsce release locked in tools/vsce supports the final token exchange, and stops with a plain error when it does not. The Entra route and the VSCE_PAT token stay as alternatives. An unrecognised VSCE_AUTH value now logs a warning, without echoing the value. The release-cycle runbook gains the setup procedure.

Changed

  • Dependabot checks the vsce packager weekly. The tools/vsce lockfile was checked monthly, so a new vsce release waited up to a month after its seven-day cooldown before a pull request proposed it. It is now checked every Monday, like the website and the pre-commit hooks, because the Marketplace publish route depends on the vsce release: Trusted Publishing needs vsce 4.1.0 or later.
  • Tool lockfile pull requests test themselves. A pull request that changes tools/vsce now packages the VS Code extension and runs the vsce release tests, and one that changes tools/channel-smoke runs the channel smoke, so a Dependabot update to either lockfile is checked before it merges. The pull request runs these checks without the full ci.yml matrix.
  • CI installs pip from a hash-locked file. Every workflow upgrades pip with --require-hashes from scripts/ci/requirements-ci-pip.txt instead of a version pin, so the download is checked against its published hash, and Dependabot proposes pip upgrades with their hashes. The same pip, 26.2.1, still runs in CI; the lock holds it at 26.2 or later, which fixes CVE-2026-13346. check_pip_pin_drift.py now checks the lock file and the workflows' install lines instead of the per-workflow version setting, and pip-audit.yml audits the lock. The PowerShell steps that install it now stop on a failed install.
  • CI installs its Python dependencies from hash-locked files. The jobs that install the project, the test tools or the engine's prerequisites now use --require-hashes with scripts/ci/requirements-ci-dev.txt, requirements-ci-runtime.txt, requirements-ci-test.txt or requirements-ci-prereqs.txt, and install the package itself with --no-deps -e ., so every download is checked against its published hash and OpenSSF Scorecard counts the installs as pinned. CI therefore tests the versions locked on the date written in each file (2026-10-29), not the newest release on the day of a run; python scripts/dev/refresh_ci_locks.py regenerates the locks, and --check compares them with a fresh compile. tests/scripts/test_ci_locks_fresh.py fails when a lock no longer satisfies pyproject.toml. pip-audit.yml still resolves the newest allowed versions each week and now audits the locks too, check_pip_pin_drift.py fails on any other workflow pip install that Scorecard counts as unpinned, and Dependabot's version updates for scripts/ci are limited to the pip lock.
  • The CI tools install from hash-locked files. ruff, bandit, pip-audit, pip-licenses and pre-commit no longer install as exact version pins. Each installs with --require-hashes from its own file in scripts/ci/ (requirements-ci-ruff.txt, -bandit.txt, -pip-audit.txt, -pip-licenses.txt and -pre-commit.txt), so every download is checked against its published hash and OpenSSF Scorecard counts the installs as pinned; only the SLSA generator's release tag and the evals workflow's Claude Code CLI install keep Pinned-Dependencies below 10. The tool versions are written once, in scripts/dev/ci_lock_table.py, and check_pip_pin_drift.py now fails on any unhashed tool install. The pip-audit lock leaves pip out, and refresh_ci_locks.py now excludes pip from every lock, because a second pip pin would replace the one in requirements-ci-pip.txt that Dependabot maintains. The pre-commit lock needs Python 3.11, which markdown-lint.yml already uses. The pip-audit lock is compiled for Python 3.11 too: the newest filelock that supports 3.10 has published advisories that only a release for 3.11 or later fixes, and Dependency review and Scorecard read a lock line whatever its environment marker says.
  • pip-audit.yml audits the new locks with OSV, on Python 3.12. The weekly run, and any pull request that touches a lock, audits the nine locks beside the pip lock. Every audit in the workflow now asks the OSV service (pip-audit -s osv) instead of pip-audit's default PyPI feed, which lists an advisory later than GitHub does: on 2026-10-29 a high advisory against virtualenv 21.14.12, published on 2026-10-23, was in OSV and not in that feed. The audits run on one interpreter, so the lines that apply only below Python 3.11 are no longer audited by pip-audit.yml; Dependabot alerts, Dependency review and Scorecard still read them.
  • ruff and mypy each have one version. ruff is pinned to 0.17.1 where pyproject.toml named a floor, and the ruff-pre-commit hook, the ruff lock and the dev lock carry the same version. mypy is pinned to 2.4.0, the version in the dev lock, and the mypy pre-commit hook moves from 2.1.0 to it. The hook also pins the dev lock's versions of click, rich, PyYAML, jsonschema and their type stubs, and no longer passes --ignore-missing-imports, so it runs mypy with the same settings as CI. tests/scripts/test_ci_tool_locks.py fails when any of these differ, so a Dependabot security pull request for either tool is adapted by hand. The tree needs no source change at either version. The ruff-format pre-commit hook now also formats Markdown files, because ruff 0.17 formats the Python code blocks in them and CI's ruff format --check . checks them.
  • The CI locks wait a week. All nine locks now wait out a seven-day cooldown that matches Dependabot's: refresh_ci_locks.py locks the files uploaded before the lock date less seven days, --cooldown-days N changes that, and --cooldown-days 0 locks every file uploaded before 00:00 UTC of the lock date, for an urgent security fix. Dependabot's cooldown does not apply to its security updates, so a row of scripts/dev/ci_lock_table.py can lift it for one package with cooldown_exceptions: the pre-commit lock takes virtualenv 21.14.13, which fixes GHSA-cx6f-vjhg-g3cc (high) but was uploaded after the cutoff. The refresh refuses an exception once the cutoff has reached its timestamp. Each lock records its lock date, cooldown, cutoff and exceptions, and --check reproduces them. The locks are at lock date 2026-10-29 with cutoff 2026-10-22.
  • The weekly vendor URL check names the hosts it cannot check. CodeBuddy's documentation host answers 0.0.0.1 to name lookups from the United States, where GitHub's hosted runners are, so the check never reached the twelve CodeBuddy pages the pins cite. It waited out three 30-second timeouts on each, about 20 of the job's 30 minutes, and counted them as unreachable. A host whose name resolves only to an address no server can hold, anything in 0.0.0.0/8 or ::, is now reported as unroutable and gets no request. Like an unreachable URL, it does not fail the check. Each run carries a warning naming such a host, and the issue the monitor files lists its URLs to check by hand.

Fixed

  • The Windsurf and Trae convention pins follow the moved vendor pages. Devin folded the Devin Desktop pages the Windsurf pin cites into a Devin Local Customizations page, a Devin Local Overview page and one Cascade (legacy) page, and TRAE moved its Chinese-edition skills page and changelog. Every citation now points at the current page, and each claim was checked against it. The Customizations page now says Devin Local finds its rules, skills, hooks and subagents the way the Devin CLI does, so the Windsurf install note no longer says the Desktop docs leave the Claude Code hook import open. The Claude Code import reads skills from the project's .claude/skills/ only, so the docs no longer say Devin may list the ~/.claude/skills/ copy too. Devin Desktop no longer starts Cascade conversations. The Windsurf rules file links the Customizations page; no file the install writes moves.
  • Dependabot can update the vsce and channel-smoke lockfiles. They moved from .github/vsce and .github/channel-smoke to tools/vsce and tools/channel-smoke. Dependabot cannot open pull requests for npm manifests under .github/ (dependabot-core#15237), so every version and security update for the two lockfiles failed and none reached a pull request. The release archives and GitHub source archives still leave them out.
  • OpenSSF Scorecard reads the workflows. scorecard.yml runs the Scorecard action with file_mode: git, so Scorecard reads a clone of the repository. It read a GitHub archive of main, which leaves out .github/ apart from dependabot.yml, so it found no workflows and reported Dangerous-Workflow, Token-Permissions, Pinned-Dependencies and Packaging as inconclusive.
  • The pipeline overview's command index is current in every translation. The docs generator wrote the index of shipped commands into the English page only, so the eleven translated overviews kept older summaries for every command. It now writes the same index into each translated page, and tests/unit/docs/test_site_generated_lists.py fails when a translation's index differs from the English one.

Security

  • The VS Code packaging tool's lockfile takes the minimatch fix. The locked vsce toolchain (tools/vsce) moves its transitive minimatch from 10.2.6 to 11.0.1, which fixes GHSA-g3hv-75wg-m249 (a denial of service through a crafted glob pattern). vsce 4.0.0 and 4.1.0 still require minimatch 10.x, which has no fixed release, so tools/vsce/package.json overrides it. vsce did not reach the affected code, which runs only at optimization level 2 or higher: it matches its own ignore list and the extension's .vscodeignore at the default level. The packaged extension is unchanged.

1.5.0 - 2026-10-28

Added

  • Windsurf and Cursor now run Apothem's session hooks. For Windsurf the install registers two Devin Local hooks in the project's .devin/config.local.json, the local override Devin documents as gitignored and excludes from git itself: the session bootstrap on SessionStart and the context-size advisory on PostToolUse. For Cursor it adds one sessionStart entry, the session bootstrap, to the project's .cursor/hooks.json. The scripts go in .apothem/support/windsurf/hooks/ and .apothem/support/cursor/hooks/. Each vendor hands extra context to the model for those events, and Apothem's write, edit and shell guards are not registered: Devin documents no context channel for PreToolUse, and Cursor documents its agent message only for a denied action. Both hooks only add context and never block. Devin runs no hook while a workspace is in Restricted Mode, and the older Cascade mode reads a different format that the install does not write. .cursor/hooks.json is your file and Cursor documents project hooks as committed, so the install adds its entry after yours, keeps your entries and keys, reports config.unparseable and leaves a file it cannot rewrite without loss, and removes only its own entry on an uninstall; the entry names the interpreter and project path of the machine that ran the install, and on a Windows host it starts with PowerShell's call operator, because Cursor's desktop app runs hook commands through PowerShell there. Cursor and Devin Local also load the hooks Claude Code wrote, so with the Apothem Claude Code install on the same machine two sets can run; the install prints the switch that turns the import off (Cursor's "Include Third-Party Plugins, Skills, and Other Configs", Devin's read_config_from.claude), the session bootstrap is delivered once per session whichever copy runs first (the vendor's own command and the Claude Code one share a marker, and a later start of the same session, such as a second compaction, still delivers), and the context-size counter is not de-duplicated. Devin sends no working directory, so its hook reads the project root from DEVIN_PROJECT_DIR. The same rules cover all five hook registrations, CodeBuddy, Kiro and Copilot included: an entry is Apothem's when its command runs .apothem/support/[<harness>/]hooks/dispatch.py with --contract <id>, whichever project path it was written under, so a renamed, moved or cloned project keeps one set of entries and a hook of yours that only shares the file name, or that runs python -m apothem.conformity.gate, is never replaced or removed; apothem verify fails once none of Apothem's entries is left in the file; an uninstall that cannot read the file reports it as skipped instead of as a success; and a project or interpreter path that holds $, a backtick, a double quote or a backslash is refused at install, naming the path, because the quoted command would run a different file.

  • CodeBuddy now runs Apothem's session and compaction hooks. The install registers two hooks in the project's .codebuddy/settings.local.json, the local settings file CodeBuddy does not commit: the session bootstrap on SessionStart and the context-size advisory on PostToolUse. The scripts go in .apothem/support/hooks/. CodeBuddy hands extra context to the model for those events and documents none for PreToolUse, so the write, edit and shell guards are not registered there; both hooks only add context and never block. Each command names the interpreter and the project path of the machine that ran the install, which is why the registration goes in the local file and not the committed settings.json. CodeBuddy does not run hooks another tool wrote until you restart it and review them in its /hooks panel, and the install prints that step. On Windows CodeBuddy runs hook commands through Git Bash only. The install merges into your file by key, keeps your own hooks and settings, and an uninstall removes only the Apothem handlers. The hook dispatcher also gained a --contract <id> option that translates a harness's event and tool names and reshapes the output for it; the harness page and the hooks reference explain both.

  • Kiro and GitHub Copilot now run Apothem's session hooks. The install registers the hooks in a hook file Apothem owns, .kiro/hooks/apothem.json for Kiro (the session bootstrap on SessionStart) and .github/hooks/apothem.json for Copilot (the session bootstrap on sessionStart and the context-size advisory on postToolUse), and puts the scripts in .apothem/support/kiro/hooks/ and .apothem/support/github-copilot/hooks/. Each vendor hands extra context to the model only for those events: Kiro ignores the output of tool events, and Copilot reads only permission fields from preToolUse. So the write, edit and shell guards are not registered there, and both hooks only add context and never block. Each command names the interpreter and the project path of the machine that ran the install, and both folders belong to the repository, so the harness pages say when to keep the file out of version control; Copilot's cloud agent runs only the bash command and finds no interpreter at that path. Kiro CLI 2.33 and later loads the hook once you trust the workspace, and the install prints that step. Your other hook files in those folders are never touched, a hook you add to apothem.json stays, and an uninstall removes only the hooks that run the Apothem dispatcher. A Kiro hook you switch off with "enabled": false stays off after an update.

  • CodeBuddy and Trae now get Apothem's helpers as their own subagents. The install writes each Apothem helper into the project as a Markdown subagent file, in .codebuddy/agents/ for CodeBuddy and .trae/agents/ for Trae, where before neither tool received the helpers. A file keeps the helper's instructions and carries the keys the tool documents: the name, the description, the allowed and denied tools as the comma-separated strings both tools read, and, for CodeBuddy only, the turn limit. A tool the tool's own documentation does not name is left out of both lists, a helper that could not edit files still cannot, and no model is set. Trae installs for the project only, because its documentation gives the user-level subagent folder as ~/.trae-cn/agents/ while every other Trae user folder is under ~/.trae/, and which one an international install reads is not confirmed. The two harness pages explain the files, the switch Trae may need, and how an uninstall treats a file of yours with an Apothem helper's name.

  • GitHub Copilot and Cursor now get Apothem's helpers as their own agents. The install writes each Apothem helper into the project as a Markdown agent file, in .github/agents/ as <name>.agent.md for GitHub Copilot and in .cursor/agents/ as <name>.md for Cursor, where before neither tool received the helpers. A file keeps the helper's instructions and carries the keys the tool documents. Copilot has no key that denies a tool, so the helper's allowed and denied tools become one list of Copilot tool aliases, and an alias that would let a helper use a tool it is denied is left out. Cursor has no tool list at all, so five read-only helpers that cannot run commands are marked readonly: true, and the seven read-only helpers that run commands drop the "read-only" label from their descriptions, since Cursor would not enforce it. No model is set for either tool. Both install for the project only; the Copilot files are part of your repository, so the cloud agent and your teammates see them. The two harness pages explain the files, and how an uninstall treats a file of yours with an Apothem helper's name.

  • Kimi Code and Windsurf now get Apothem's helpers as their own subagents. The install writes each Apothem helper into the project as a Markdown subagent file, in .kimi-code/agents/ for Kimi Code and in .devin/agents/ for Windsurf's Devin Local agent. Kimi Code kept the helpers in a support folder where it never loaded them; the first update or uninstall after this release removes that old folder, .kimi-code/.apothem/support/agents/, after saving a copy under ~/.apothem/backups/. Windsurf received no helpers before. Both tools spell tools their own way, so the install translates them. Kimi Code gets lists of its own tool names (WebFetch becomes FetchURL, TodoWrite becomes TodoList, and a name Kimi Code has no tool for is left out). Devin has no key that denies a tool, so a helper's allowed and denied tools become one lowercase allowed-tools list, and Bash becomes exec. Windsurf gets eleven of the fourteen helpers: Devin documents no tool name for web search or web fetch, so citation-auditor, fact-checker and research-scout wait until it does. No model is set for either tool, and Kimi Code never gets override. Both install for the project only. Kimi Code uses a helper when you ask for it by name, since its 2.3.2 release stopped delegating on its own, and Devin labels custom subagents experimental and puts them behind a Subagents (Preview) setting. The two harness pages explain the files, and how an uninstall treats a file of yours with an Apothem helper's name.

  • Kiro now gets Apothem's helpers as its own custom agents. The install writes each Apothem helper into the project as a Markdown agent file in .kiro/agents/, where before Kiro received no helpers. The files are for Kiro IDE 1.0 and Kiro CLI V3 (kiro-cli --v3), the versions that read the Markdown format; no JSON profile and none of the older CLI 2.x keys are written. A file keeps the helper's instructions and carries the name, the description and one list of Kiro tool categories (read, write, shell, web, subagent). Kiro has a single list for tools, so a helper's allowed and denied tools are folded into it, and a category that would let a helper use a tool it is denied is left out. No model is set. The install is for the project only, and Kiro does not load a project's agents until you trust the workspace. The Kiro page explains the files, the trust step, and how an uninstall treats a file of yours with an Apothem helper's name.

  • The Marketplace publish can sign in with Microsoft Entra ID instead of a stored token. publish-vscode.yml now picks its credential in a Select Marketplace credential step. With the repository variables VSCODE_MARKETPLACE_READY=true, VSCE_AUTH=entra, AZURE_CLIENT_ID and AZURE_TENANT_ID set, the job signs in through a GitHub OIDC federated credential (Azure/login, pinned by commit, no client secret) and vsce publish --azure-credential publishes with a short-lived token; the Entra steps never receive VSCE_PAT. Without those variables the VSCE_PAT secret publishes as before, and the credential is a switch, not an automatic retry. When VSCE_AUTH=entra is set but the client or tenant id is empty, the run logs a warning whether or not VSCE_PAT is set. The two switch variables are compared without regard to case. On the Entra route, a manual dispatch with the new dry_run input signs in and verifies publisher access without publishing; on the token route it warns that nothing was verified. The publish job now holds id-token: write. The release-cycle runbook gains the Azure and Marketplace setup procedure, which marks the facts no primary source confirms.

Changed

  • The docs site's Node type definitions match the Node it runs on. @types/node moves from 25 to 22, the major of the site's Node floor (engines and .nvmrc), so the type-check no longer accepts Node APIs that Node 22 lacks. Dependabot stops proposing @types/node major updates for the site; raise that major together with the floor.

Fixed

  • The licensing gate runs on every change. reuse lint ran only inside the license audit, which starts on dependency and license file changes, so a test added with a fixture line the REUSE parser reads as a malformed license expression reached main unnoticed. The gate now has its own workflow, reuse.yml, on every pull request and push to main, and the release readiness check requires it green. The fixture line is now marked for REUSE to skip.
  • Dependabot assigns its pull requests without a warning. The assignee in .github/dependabot.yml now spells the maintainer's login with GitHub's own capitals. The assignable-users lookup Dependabot runs is case-sensitive, so the lowercase spelling made it comment that the user "could not be added" on every pull request, although the assignment itself went through.
  • The workflow audit's open finding is resolved with its reason. zizmor's self-repository audit asks the test matrix to call its reusable workflow with GitHub's $/ form, which the pinned actionlint does not accept yet. The call keeps ./ with an inline ignore that records why neither of the audit's risks applies, and the zizmor workflow's egress note now describes how the current action installs zizmor (a hash-locked wheel from PyPI).
  • Switching the docs language in the page now updates the page's language and direction. The language switcher moves between locales without a page load, and the site set <html lang> and dir only when a page first loaded, so after a switch from German to Arabic the Arabic page stayed marked German and laid out left to right. A client component now applies the new page's language tag and direction after every navigation, before the page paints. Search already followed the switch.
  • The conformity gate no longer reports on files that belong to another checkout. Validators that walk the repository from its root descended into nested git checkouts (a worktree under .claude/worktrees/, a submodule, a nested clone), so agnosticism-grep failed the strict gate on the AGENTS.md copies inside a worktree, and the same walk entered site/node_modules, which stretched a strict run past ten minutes. One shared tree walk in _grep_base.py now skips any directory that holds a .git file or directory, plus the vendored, virtual-environment, cache and build-output trees (node_modules, _vendor, venv, dist, .next and similar), wherever they sit. agnosticism-grep, agents-md-coverage-grep, dynamism-grep, freshness-token-grep, plain-language-grep and reference-token-grep use it; the stray-suite sweep in no-global-plans-grep keeps its own walk and now also stops at a nested checkout. Validators that read one fixed folder, such as naming-grep, are unchanged. In a single checkout the findings are the same, except that a file under one of the pruned directory names is no longer read. freshness-token-grep and reference-token-grep now list their findings in directory order instead of one pass per file suffix.

Security

  • The VS Code packaging tool's lockfile takes the qs fix. The locked vsce toolchain (.github/vsce) moves its transitive qs from 6.16.0 to 6.16.1, which fixes GHSA-6pq8-jhm2-2vcw (an uncaught error in qs.stringify with the comma array format). The tool runs only in the release and publish jobs; the packaged extension is unchanged.

1.4.0 - 2026-10-26

Added

  • Gemini CLI helpers can reach an MCP server you name. The agent_mcp_servers key now also reaches the Gemini CLI install: for each listed helper, its tools allowlist gains one mcp_<server>_* entry per server, the form Gemini CLI's subagent docs give, and no other helper changes. Gemini CLI cannot address a server name with an underscore, so Apothem writes a grant only for a name of letters, digits and -; any other name is skipped and reported rather than rewritten. A server the helper's own disallowedTools names stays denied, as it does on Claude Code, and a helper that already reaches every server is left as it is; both are reported. With no setting the helpers are written exactly as before.
  • A stricter research method, end to end. The research suite gains seven reference guides and uses them at the stage that needs them, without adding a rigor mandate:
    • design fixes the experimental unit, allocation and its concealment, masking, nuisance factors and run order, control conditions, and within-unit and multi-factor structure (study-allocation-and-structure.md), and sizes the study for the analysis it will run: the effect range, sidedness and allocation ratio, multiplicity, attrition, clustering, sequential looks and simulation where no formula fits (power-and-sample-size.md);
    • analysis picks tests from the design, counts independent units, states its missing-data handling, reads a null result without observed power, holds a Bayesian plan to its priors and diagnostics, and rates bias per result (analysis-discipline.md); figures disclose binning, smoothing and normalisation, carry a cue beyond colour and keep experimental images traceable (figure-integrity.md);
    • source collection keeps a search record (queries as run, filters, dates, counts, chaining backward and forward, a pass for contrary evidence), links reports of one study, and carries each source's retraction and correction status through to the paper and the submission (search-record.md);
    • the proposal stage reads a funder call into a requirement matrix, answers a critique with --resubmission, plans data management and sharing, and gives each risk a contingency with an owner, a review date and a trigger (plan-branching-and-contingencies.md); publication and dissemination record each venue rule with its source and date, count pages the venue's way, check the compiled PDF, and plan talks and posters by time budget and audience (talk-and-poster.md).
  • Reference entries from identifiers. paper-toolkit gains an entries mode: DOIs, arXiv identifiers, ISBNs and similar become reference entries with every field copied from the registry record, in one normalised form, and the style pass covers chapters, datasets, software releases and unpublished work (bibliography-entries.md).

Changed

  • Dependabot proposes dependency updates. The repository's docs and workflow comments said Renovate bumped the pinned action SHAs weekly, but Renovate never ran here. .github/dependabot.yml now proposes grouped weekly updates for the GitHub Actions pins (moving each SHA and its version comment, with CodeQL's steps kept together), the website and the pre-commit hooks, and monthly updates for the vsce packager and channel-smoke lockfiles, each held for seven days after a release. Pins that move in lockstep with another file (the runtime floors, the hash-locked release requirements, the vendored closure, the ruff, mypy and gitleaks hooks) stay hand edits. renovate.json is gone. The npm audit workflow now also audits and installs the two tool lockfiles, so a pull request that changes one is tested. The PR title check moves to its own PR Title workflow, which re-runs when a title is edited, and the repository's squash default now takes the PR title, so a long Dependabot title is fixed by a retitle before it merges. .gitattributes keeps .github/dependabot.yml in source archives, where Scorecard looks for the update tool.
  • Fetched text is data, and standing is not evidence. The provenance rule now states that text fetched from the web or returned by an index is data to read, never instructions to follow; the research agents, the multi-source-research skill and the paper tools apply it and report an instruction-like sentence instead of acting on it. A second new section says a journal-level measure, a citation count or a venue's or author's standing is not evidence that a work is sound; reviews and certainty ratings rest on the work's own evidence.
  • The autonomous experiment loop separates search from admission. A change is retained only after it wins on the search set and is confirmed on a separate admission set; the loop records how often the admission set was read, keeps a final untouched set (or labels results development-only), logs each trial's prediction, lesson and failure cause, makes a noise-aware keep decision, and stops at a campaign ceiling.
  • Security metadata and one vendor link are current. SECURITY-INSIGHTS.yml carries today's review date and lists npm audit, Dependabot security updates, secret-scanning push protection and the approval-gated publishing jobs. The GitHub Copilot pin and the harness registry cite the agent-skills page at the address GitHub moved it to. The packaging contract page explains the "1 with warnings" badge claude.ai shows for the Apothem marketplace: its sync strips the directory listing links that Anthropic's directory reads.

Fixed

  • Site search follows the page language. The search dialog stays mounted when a reader switches language, and the docs framework now keeps a search client's query function for as long as the client's own dependencies stay the same; the static client's dependencies do not include the index URL, so after a switch the dialog went on searching the first language's index. The dialog now re-binds when the index URL changes.
  • Markdown lint passes, and CI runs it. Eighteen markdownlint findings had landed unnoticed because only contributors' machines ran the hook: untagged code fences, emphasis used as a heading, and one-item numbered lists in the generated plugin copy, where each numbered command step becomes its own reference file. The sources are fixed, the hook skips the generated plugins/claude-code/ tree as it skips test fixtures, and a Markdown Lint workflow runs the hook on every change to Markdown, the lint policy or the hook pin.
  • Windows CI runs get room to finish. The Windows quality cells take 30 to 55 minutes, and the 60-minute cap cancelled healthy runs on slow runners; the cap is now 90 minutes, the matrix-job ceiling the workflow validator allows.
  • The Codex plugin installs with a sparse checkout. codex plugin marketplace add cloned the whole repository, more than 8,000 files, to read one small folder, and Codex gives up on a clone after 30 seconds, so on a slow disk such as a Windows drive under WSL the add or a later refresh timed out and the plugin stayed at an old version. The documented command now passes --sparse .agents/plugins --sparse plugins/apothem, the channel smoke runs it, and the troubleshooting page shows how to re-add an existing marketplace.
  • Uninstall removes an unedited copy of an earlier release's template. Uninstall deleted a plain operator-owned file such as glm.toml only when it matched the current template, so a release that changed the template left every unedited copy an earlier release wrote in place, as if you had edited it. A manifest entry now lists the SHA-256 digests of the templates earlier releases shipped (earlier_digests), and uninstall deletes such a copy when Apothem's install record shows it wrote the file. Without a record, only an exact copy of the current template is removed, as before, and a copy you placed is always kept. glm.toml records the digests of the templates from v1.0.1 through v1.2.2. A test fails when a shipped template changes without its previous digest recorded, and the release-preflight job checks the record against every release tag and fails once a newer release exists, until the record is refreshed.

1.3.0 - 2026-10-25

Added

  • Four skills. knowledge-wiki grows an index-first Markdown knowledge base from project sources (each source page records what was actually read, relations carry a confidence, and lint, drift and hub reports keep it honest); decision-matrix chooses between options with weighted, evidence-cited scores, dealbreakers first and a check that the winner survives weight changes; issue-lifecycle takes an issue from a duplicate-checked draft through sizing and a marked failing-test checkpoint to a fix (you run it; it never files on its own); ui-design designs and refines interfaces to a craft floor with a DESIGN.md project context.
  • Two read-only subagents. citation-auditor verifies references and whether each cited source says what it is cited for; design-critic reviews an interface with heuristic scoring and measured accessibility evidence kept apart, and says so when the evidence could not be gathered.
  • Two path-scoped rules. authoritative-referencing-provenance asks research files to label how each claim's evidence was read and keep a search record; code-craft-ui carries the interface craft floor onto UI source files.
  • Sharper research, review and planning stages. Source pages record their basis and an acquisition worklist; papers get an approved argument sketch before prose; reviews run a constructive then an adversarial pass and can pre-screen against a venue profile; rebuttals can be checked against the revision; a published archive is downloaded and verified. Audits and code review accept "no findings", review deletions too, and keep a ledger of findings dropped in verification. Plan execution ties each gate to the commit it ran on, and tests and evals include a control that must fail.
  • Paper work without a research suite, a viewpoint panel, and course material. paper-toolkit writes a reading note that records what was actually read, compares two to five papers (saying when results are not directly comparable and which paper to cite for which claim), drafts related work from the sources you supply with a coverage report and visible citation-needed markers, critiques a draft before submission, and runs a reference style pass. perspectives runs several separate viewpoints on a contested question, then reconciles them into agreement, real disagreements, a recommendation with its confidence and the strongest dissent. teaching-pack turns one paper or technical document into learning goals, a curriculum, formula walk-throughs, worked examples, a quiz with an answer key and a glossary, marking every line with its source section and reporting thin parts instead of padding them. /research-review --paper reviews a PDF or text you supply, outside any suite, against a generic venue profile with reviewer roles and equation, ablation and baseline checks. authoritative-referencing-assurance asks research files to list a proof's assumptions and weakest step, bind each number to its run, name the closest prior work behind a novelty claim, state tool and model use, and fix a gate's definition before results are seen; /research-publish drafts the tool and model use statement from the session record, and the provenance rule now asks that a check be shown to fail when its target is altered, that success be matched on the whole token, and that a lookup connector which never loaded be listed as blocked. gate-evidence-grep is an advisory conformity check that flags plan gate claims recorded without a command, an exit status or output, and the commit it ran on. issue-lifecycle can draft a request to the reporter for missing details and, only when you name the publish stage, open a draft pull request after three separate confirmations. citation-auditor and research-scout use a scholarly lookup server you grant them and fall back to web lookup. The session-start hook adds one line when a project's knowledge base has changed since its recorded baseline.

Changed

  • Claude Code sessions start with about 6K tokens of rules, not about 58K. Four rules stay loaded in every session (agnostic posture, authority and inquiry, session closure, context management), with a short rule index that names every other rule and when to read it. The other 24 rules that loaded at launch now load when a matching file is read or edited, or when a skill that cites them runs. Installed rule copies leave out their ## Bindings cross-references, which stay in the source, and a plugin-only session is told to read the same four rules first.

  • Read-only skills and commands are model-invocable; side effects stay manual. 35 audit, review, planning, research and authoring commands and skills can now be chosen by the model when a request matches them. Commands that edit, publish, release or rotate secrets (elevate, fortress, freshify, both GitHub deploy commands, release-readiness, workflow, plan-execute, research-experiment, research-publish, dependency-upgrade, secret-rotation and issue-lifecycle) run only when you invoke them. plan-suite and research-suite are reference templates read by path and are not listed. Every description now leads with what the skill does and the requests it serves, in about 300 characters (the 55 model-invocable descriptions total about 15,800 characters; the 52 that predate this release's three new skills went from about 42,000 characters to about 15,000 by trimming), and overlapping skills, commands and subagents name where each neighbouring request goes instead.

  • Session start lists the skills by task. A short generated index (one line per domain, about 400 tokens) reaches Claude Code at session start, so the model still knows a skill exists when its harness drops descriptions from a long skill listing. scripts/dev/generate_skill_index.py --check keeps it in step with the catalog.

  • OpenClaw and Hermes load Apothem's skills without hand wiring. Install adds Apothem's support skills folder to OpenClaw's skills.load.extraDirs and Hermes's skills.external_dirs, after any entries you already have; uninstall removes only that entry, and verify checks it. Both lists come last in their tool's lookup order, so a skill of your own with the same name is the one that loads. A commented openclaw.json or config.yaml that lacks the entry is refused with the line to add, as for OpenCode and Qwen Code.

  • research-scout and citation-auditor keep a read-only tool list and reach a scholarly lookup server only when you name it. Their tools list stays Read, Glob, Grep, WebSearch, WebFetch, so with no setting they reach no MCP tool and use the open web. A new profile key, agent_mcp_servers, maps an agent name to the MCP servers it may call, and the Claude Code install adds one mcp__<server>__* entry per server to that agent's list and to no other agent. Server names allow letters, digits, -, _, : and .; * and any other character are rejected, and a grant naming an unknown agent is reported and skipped. The plugin install reads no profile and keeps the plain list; a plugin user can get connector access with a user-level agent of their own. Other harnesses ignore the key.

  • Qwen Code reads Apothem's skill tool lists. Skills now carry allowedTools as a list, the key and shape Qwen Code reads; it ignores allowed-tools and rejects a comma-separated string.

  • Codex helper files carry only keys Codex reads. They no longer set sandbox_mode = "read-only", which Codex ignores in a custom agent file: the session's own sandbox governs writes, and each read-only helper states it in its instructions.

  • Shared-folder advisories cover more readers. Install now notes that Qwen Code also reads ~/.agents/skills/ (OpenClaw only under its default state directory) and that Cursor reads ~/.claude/agents/ and ~/.codex/agents/.

  • Native config merges refuse a shape they cannot merge. Where your file holds a scalar or a different kind of value at a key Apothem writes a list or mapping to, install refuses and writes nothing instead of replacing your value; an explicit null counts as absent.

  • Hook messages point at files the model can open. Mandate, gate-bar and section references in the text hooks inject either name the shipped rule file they come from or say what they require, so they still mean something under a plugin install, where the rules are not loaded. No message grew.

  • Kimi Code loads Apothem's skills natively. Skills and command skills now install to the project's .kimi-code/skills/, the folder Kimi Code reads, instead of a support folder it never scanned; update and uninstall clear the old copies, so each skill exists once. Helper definitions stay in the support folder until their tool names are mapped, and hooks are not written because Kimi keeps them in a user-level TOML file Apothem cannot yet edit and undo safely. A skill of yours with the same name as an Apothem skill is replaced after a backup.

  • The Codex plugin ships a root plugin.json. The plugin now declares the Agent Plugins schema in plugin.json at its root, the format Codex documents for new packages, and keeps .codex-plugin/plugin.json as the documented fallback. The marketplace entry carries the policy block Codex asks for.

  • Claude Code receives commands as skills that survive compaction. The plugin and the engine install now ship each command as a skill: a SKILL.md of at most about 5,000 tokens with the procedure the model needs every time, plus references/ files for the pipeline contract, standing stanzas, decision tree and, for the longest commands, individual workflow steps, each behind a pointer that says when to read it. Claude Code keeps only the first 5,000 tokens of a skill after compaction, so the later steps of long commands such as /apothem:plan-execute were lost before. Commands are still invoked as /apothem:<name>; other harnesses are unchanged. Extra frontmatter keys now sit under metadata.

  • Hooks run one dispatcher per tool call, not one per guard. On every surface (the Claude Code plugin and engine install, Codex, Qwen Code) each event and matcher now has one dispatcher entry that lists every guard it evaluates; one process reads the payload, runs them all, and returns one envelope. The plugin's bootstrap also caches the interpreter it found, so the PATH probe runs once instead of before every tool call. Measured on Windows, a Write went from five hook processes of about 1.5 seconds each to one of about 0.45 seconds. The compaction tracker runs in the background, so it no longer delays any tool result.

  • A guard that fires says only what it found. It injects the short ## Advisory section of its message, filled with the path, identifier or primitive it matched, plus a pointer to the full procedure, instead of the whole message (2 to 7 KB). A guard that finds nothing stays silent.

  • The compaction advisory measures the context. It reads the context size from the session transcript and asks the assistant to save state at half the window and again at three quarters, when it also tells you the session is long (at 120,000 and 250,000 tokens when the window is unknown; set APOTHEM_CONTEXT_WINDOW_TOKENS to give it). A compaction restarts its two-advisory budget. The old activity counters remain the fallback where no transcript exists.

  • The git-write reminder is a check. It fires only when the command carries a plan-internal identifier, a numeric prefix on a suite-root plan file, or agent-attribution text, and names the finding.

  • One tagline and token-aligned marks. The README, landing page, brand page, wordmark lockups and social images carry the tagline "one profile, every harness", and the logo, favicon, social images and animated mark use the design-system colour tokens; a light animated mark joins the dark one, and scripts/dev/rebuild-assets-resvg.py rebuilds every raster from its source.

  • make lint also runs mypy. The target now matches the lint gate the docs describe: ruff check, ruff format --check and strict mypy.

  • Cursor, GitHub Copilot, Windsurf, Zed, CodeBuddy, Kiro and Trae get Apothem's skills and rules. Installing any of them writes the skills, and each command as a skill, once to ~/.agents/skills/ (which Cursor, Copilot, Windsurf, Zed and Codex read) or to the tool's own folder (~/.codebuddy/skills/, ~/.kiro/skills/, ~/.trae/skills/), and the rules and templates they cite to ~/.config/apothem/. A project still gets only its one rules file, which names those folders. Every install writes the same files; uninstall keeps a folder while another install still uses it and says which one. A write failure in your home stops that adapter's install before the project changes, a skill folder of yours with an Apothem skill's name is skipped with a warning, and folders are staged and renamed into place so an interrupted install leaves nothing half-written. Codex's skills now always go to $HOME/.agents/skills, even when CODEX_HOME points elsewhere. Trae's China edition, each tool's handling of unknown skill keys, and Zed's skill-count limit are not yet confirmed.

Removed

  • Funding links. .github/FUNDING.yml and the Funding URL in pyproject.toml are gone; the project takes no sponsorship.

Fixed

  • The question guard names questions from one and reads "destructive" as the rule does. Its findings said [Q2] for the third question; they now count from one. A recommended option is flagged as destructive for the operations the questions rule lists (delete, overwrite, revert uncommitted work and their synonyms) and for dropping a table or database, not for words like "retire" or "drop it from the copies".

  • The GLM adapter describes Z.ai's own coding tool. Z.ai ships ZCode, an agentic development environment; the docs and the glm.toml template no longer say it ships none, and say this adapter configures GLM only as a model backend. The template's model mapping stays a placeholder because Z.ai's pages give conflicting values. An unedited glm.toml written by an earlier release no longer matches the template, so uninstall leaves it in place.

  • The dynamic-evaluation guard ignores prose. A call now needs its parenthesis right after the name and an argument, definitions named eval or compile are skipped, a shell eval must start a statement and expand something, and a command that only searches or commits is not scanned. yaml.load with a SafeLoader anywhere in its arguments is quiet. Text such as "eval (one-off)" no longer raises an advisory.

  • The authorship-header guard works under the plugin. It used to stay silent there because its checker needed the full package. A small standard-library checker now reads the header and exemption lists from the installed tree. It speaks only in a project that carries Apothem's own header fixture, so it never asks for an MIT line in your project, and an edit fires only when it would create a file without the header or remove one.

  • The plans guard no longer fires on the project's own plans tree. It judged "inside the project" against the tree the plugin is installed in, so every write to <project>/.apothem/plans/ under a plugin install looked global. It now uses the git root above the tool call's working directory.

  • The Bash plans guard inspects what a command writes. It matched any command that mentioned a plans path, including ls and mkdir; it now classifies the targets of redirects, tee, touch, the destination of cp, mv and install, and the PowerShell write cmdlets, resolving relative paths against the command's working directory. Heredoc bodies and comments are not read as commands, and network (UNC) paths are never resolved.

  • Codex apply_patch writes are checked. The plans and isolation guards read the targets named in the patch body, as the dependency guard already did.

  • The isolation scan skips non-product files and public identifiers. Writes outside the project or into its .apothem/ working tree are not scanned, and UTF-8, SHA-256, ISO-8601, CVE-… and RFC-… no longer read as plan identifiers.

  • /.well-known/security.txt is published. The Pages upload left out dot-prefixed paths, so the file returned 404; the site workflow now uploads it, allows no other hidden path, and checks the archive holds it. The site copy's Expires matches the root copy.

  • The docs match the code again. Install examples for project-scope harnesses name the project, the verify and doctor pages describe what the commands do, TRANSLATING.md describes the machine-seeded locale pages as they are served, broken links are fixed, and internal decision ids no longer appear in shipped commands, rules or templates.

Security

  • Release build tooling updated for two advisories. The hash-locked build environment moves to certifi 2026.10.19 (PYSEC-2026-4320, a distrusted root certificate) and setuptools 84.1.0 (GHSA-xmj3-9gf7-h52w, a legacy wheel-install path), and build-system.requires pins the same setuptools. Neither advisory reaches an Apothem install: the setuptools path is reached only through the deprecated setup_requires mechanism, which Apothem does not use, and the build environment's certifi is not shipped.
  • Documentation site dependencies updated for three advisories. The site moves to next 16.4.3 (GHSA-2464-fhr4-w9xw, GHSA-p3m5-59mp-jv5r, GHSA-673q-mjm6-r5xr) and zod 4.6.7 (GHSA-mrhx-c7xc-m3w5). None reaches the published site: it is a static export with unoptimized images, no server actions and no use cache functions, and zod validates page frontmatter only at build time.
  • VS Code publishing tool updated for one advisory. The locked vsce toolchain overrides @azure/msal-node to 7.1.1 (GHSA-xcx6-jx8p-x3h5), since @azure/identity still requires the 6.x line. The publish step signs in with a personal access token and never reaches the affected authorization-code flow; the packaged extension is unchanged.

1.2.2 - 2026-10-20

Added

  • The VS Code extension is on the Visual Studio Marketplace as ahmed-g-gad.apothem-vscode, named "Apothem for VS Code". Install it from the Extensions view or with code --install-extension ahmed-g-gad.apothem-vscode; the signed apothem.vsix attached to each GitHub Release installs the same extension. The channel smoke installs it from the Marketplace too.

Changed

  • The extension's identifier is ahmed-g-gad.apothem-vscode. The Marketplace already holds the name apothem, so the extension takes a new one. A copy installed from an earlier apothem.vsix keeps the identifier ahmed-g-gad.apothem; uninstall it (code --uninstall-extension ahmed-g-gad.apothem) so the two copies do not both register the same commands.

Fixed

  • The provenance check verifies the VS Code extension's signature. verify-provenance.sh and verify-provenance.ps1 checked the release assets named apothem-*, which left out apothem.vsix and its signature bundle. They now verify it, and fail when a release ships the extension without one.
  • The release runbook covers every step its readiness check and publish approval need. A release commit changes none of the paths that start CodeQL and Conformity, so the runbook now starts both on the release commit before tagging. It also shows how to approve the release environment: the GitHub Release publish first, then npm and the VS Code extension once check-release-ready.sh passes. The publisher-account runbook approves the GitHub Release publish before it runs the check, too.

1.2.1 - 2026-10-19

Changed

  • /plan-audit runs on a suite that has only a spec. Its Sequence Gate required a generated suite, while its own steps delegate a missing suite to /plan-generate. It now refuses only when neither an authored spec nor a generated suite exists, and then points at /plan-spec. Its argument hint and page no longer offer --from, --remediate and --maintenance, which the command never defined; --cap N and --dry-run remain.
  • The file-header check blocks. It reported advisory findings until the tracked tree had none. The last two files now carry the header, and the injector smoke-test inputs, which stay header-less on purpose, are on the exception list. Under --strict, as CI and the pre-commit hook run it, a file without the SPDX header line now fails the run.
  • The security policy states how long older minors get fixes. SECURITY.md lists 1.1.x as receiving critical security fixes only, until 2027-04-15, and 1.0.x as unsupported. 1.2.x receives every fix.
  • The translated documentation names each concept the same way throughout. Each of the eleven translations rendered some English terms two or three ways. Every translation now follows its language's glossary, or the most common rendering where the glossary has no entry.

Fixed

  • A new user can complete the verified one-shot install. The installers stop until the maintainer's public key is in the keyring, and told users to check a fingerprint that SECURITY.md did not publish. SECURITY.md now publishes the signing key, its fingerprint and where to get it. The README and install pages show the one-time import before the installer (on Windows through Git's own bash, whose keyring git verify-tag reads), and the installers' stop message gives the exact commands. The channel smoke runs the documented import first, and on Windows it stops the gpg daemons so its temporary home can be removed and the run reports its result.
  • More documentation and metadata match the code. The pipeline pages for /plan-audit, /plan-execute, /research-analysis, /research-paper, /research-publish and /security-audit now state the gates, outputs and options their commands have. The CLI reference covers how --harness all treats exclude_harnesses, every token prefix the MCP warning flags, what a dry run reports, and that --verbose adds nothing to doctor and uninstall. The Claude Code page warns which ~/.claude/ folders every install removes and how to restore them. Pages on CI, the self-contained runtime, the release cycle, uninstalling, troubleshooting and the deployment checklist are corrected. In the code, the Claude Code and Kimi Code capability notes, the compatibility matrix and the adapter-shape rule now match what the adapters do.
  • The header injector keeps line endings. scripts/inject-header.py --mode fix-in-place rewrote an LF file with CRLF line endings on Windows. It now writes each file back with the line ending it had.
  • The GitHub Copilot convention pin cites the current page. Its evidence for the Copilot CLI's web_fetch tool cited a page that had moved and no longer described the tool. It now cites the page that does, and drops a detail that page does not state. The recorded capability is unchanged.

1.2.0 - 2026-10-15

Added

  • Each install says where Apothem's support files are. The instruction file an install already writes (or its profile document) gains an "Apothem support files" section that names the directory each rules/, templates/, schemas/, hooks/, and conformity/ citation resolves against, derived from the propagation manifest.
  • The Claude Code plugin ships the four output styles, in the plugin's output-styles/ directory.
  • apothem backups prune runs backup and ledger retention on demand (--keep N, --harness NAME|all, --dry-run, --json). It never removes the backup set that rolling back a harness's latest install restores from.
  • A weekly check follows every vendor URL the harness pins and templates cite, and reports one that has moved or died on a single open issue. A timeout, a refused connection or a passing outage is listed but does not count as dead; a host name that no longer resolves does.
  • The one-shot installers offer a checksum-only path. APOTHEM_VERIFY=checksum installs the release's platform archive after checking its SHA-256 against the release's SHA256SUMS, aborts on a mismatch before extracting anything, and states that a matching digest proves integrity, not who published the archive. It is the documented alternative to APOTHEM_ALLOW_UNVERIFIED=1 for a host without the maintainer's public key.
  • Every --json object carries schema_version, and the profile schemas are served at their $id URLs. harnesses list --json stays a JSON array, so it has no top-level key to carry the version.
  • doctor probes each installed harness's hooks and accepts --project.
  • CI runs the npm shim on Node 18, 20, 22, and 24, under a written runtime-floor policy with an end-of-life notice.
  • Installs name the other tools that load a shared path. The registry records one owner for each path several tools read, and installing an owner or a reader prints a note naming the others.
  • Install warns about risky MCP profile entries: transport: sse, plain http:// to a non-loopback host, and token-shaped literals in headers or env, without printing the value.
  • The Qwen Code extension ships a Markdown bootstrap command.
  • Every slash command has a generated docs page and nav entry, and the command index, CLI list, and conformity-validator table are generated from code. Translated pages whose English source changed since translation show a staleness note.
  • A channel smoke workflow runs every documented install command anonymously. channel-smoke.yml runs on a weekly schedule and on demand. Each of the eight install channels runs on a clean runner with only its documented prerequisites, an isolated home directory, no credentials, and Git prompts disabled, so a private repository, an unpublished listing, or a missing release asset fails the job instead of reaching a new user. The commands live in scripts/dev/channel_smoke.py, and a test keeps them equal to the README. The harness CLIs install from a hash-pinned lockfile, which overrides Qwen Code's sharp 0.35.4 with 0.35.5 for GHSA-wq5f-xc86-pv6w.
  • The README explains the Qwen Code plugin prompt. The repository is also a Claude Code marketplace, so Qwen Code asks which plugin to install; qwen extensions install ahmed-g-gad/apothem:apothem --consent installs without the prompt.
  • A behavioural eval suite ships as plain data. evals/ holds 108 cases in the plugin-eval format: trigger and non-trigger cases for every model-invocable command and agent, one outcome case per /plan, /research, and /audit stage, and paired rule-effect cases. evals/case.schema.json and a test validate every case, and a manual-dispatch, cost-capped Evals workflow runs them on demand.
  • CI records per-commit metrics. A metrics job runs scripts/dev/collect_metrics.py and enforces separate coverage floors for the engine (80), the conformity gate (81), and the audit tooling (70). It also reports launch-time bytes per harness, CLI cold start, and hook latency.
  • Property tests cover the profile loader and frontmatter parsers.
  • scripts/release/bump_version.py moves every version anchor in one step. CI also checks the CHANGELOG link definitions, and the release build stops a tag whose plugin changed without a version change.
  • The plugin manifest carries a display name and listing links.
  • A binding-five-direction-grep validator gates the Bindings section, and every conformity entry point answers --help.
  • Brand and README pages carry a trademark and non-affiliation notice for third-party harness names.

Changed

  • OpenCode loads the always-on rules only. opencode.json instructions lists the profile document and the 28 alwaysApply rules by path instead of globbing all 91, which cut OpenCode's launch context from 914,285 bytes to about 216,000. Install and update replace the old glob, and uninstall removes it; your own instructions entries are kept.
  • A skill and a command that share a name install as the skill (projectify, workflow), in the engine install as in the plugin.
  • The single-file rule anchors no longer point at the Apothem source repository; they say which Apothem files the install placed.
  • CI bounds cyclomatic complexity. The CLI and the install driver block any function above 15, and a repository-wide ratchet stops any function from growing past the current maximum. The longest command bodies are split into phase helpers with no change in behaviour.
  • Helpers used across packages have public names: capability_projection_results, is_apothem_hook, and configure_stdio. The private spellings remain as aliases.
  • Install refuses to rewrite a config it cannot keep intact. A merge that must change a commented, JSONC, JSON5, or unparseable operator config writes nothing for that harness and exits 1 with config.unparseable; a merge that changes no value leaves the file byte-for-byte as it was.
  • Backups and the install ledger stay bounded. Each harness keeps its newest 10 backup sets, one per install, uninstall or rollback, plus any older set a kept install, uninstall or rollback record still references, and the ledger keeps the newest 10 installs per install root. A root with nothing installed keeps its last record, so the backups of its last uninstall or rollback stay until that root sees another operation.
  • Harness convention pins cite their vendor sources. Each pin lists the pages it rests on with retrieval dates and gives every discovery-pending capability a dated target. CI and the release build block on a pin older than 90 days, a pin with no vendor URL, or an overdue target.
  • Capability rationales match the vendor docs. GitHub Copilot, Kiro, Trae, CodeBuddy, and Devin rationales cite the command and agent surfaces those tools document; Antigravity skills and Gemini CLI memory are native; Cursor web fetch is supported; the CodeBuddy and Devin MCP paths are corrected.
  • Each converted cohort declares what it keeps or drops. Every adapter that converts commands, agents, or rules records a conversion_losses map in its capabilities.yml, checked against real converted output, and Gemini CLI command prompts no longer start with the source frontmatter.
  • Skill and command descriptions stay within 1,024 characters, the Agent Skills limit, and the schemas enforce it.
  • The commands README records each command's model-invocation setting, and a test keeps the table equal to the command files.
  • Usage errors exit 64 with a cli.usage envelope under --json, distinct from a findings or partial-write exit.
  • quickstart asks for a harness instead of configuring all seventeen; --harness all keeps the old behaviour. The first install creates the default profile.
  • doctor judges installed harnesses only, and profile validation reports every error.
  • The GitHub Copilot instructions put the operator profile first.
  • Shared instruction files carry harness-neutral text. The Kimi Code AGENTS.md block and the Gemini CLI and Antigravity GEMINI.md blocks no longer present themselves as one tool's own file.
  • The harness docs state what each tool loads. The Claude Code pages match what the adapter writes, the install page gives the plugin's /apothem:<name> command names, and the OpenClaw, Hermes, and Kimi Code pages cite the vendor docs. The comparison page is dated and sourced.
  • The session-end protocol is now opt-in. A Stop hook that returns context makes the assistant take another turn, so the protocol cost one extra turn in every session, whether or not the operator asked for it. Set APOTHEM_SESSION_END_ENABLED=1 to enable it. It never fires on a stop that already follows a hook-driven continuation.
  • Gate iteration and pipeline remediation are bounded. The pre-emission gate's revise-and-re-run loop stops after three rounds and reports BLOCKED with the failing bars, and every command that iterates on the gate says so. /plan and /research take --max-rounds N (default 3) for per-stage remediation, matching /fortress.
  • The proactive-compaction advisory fires at most twice per session and can be silenced with APOTHEM_PROACTIVE_COMPACTION_ENABLED=0. Its model-facing text now asks only for state externalization; the compaction suggestion goes to the operator, who owns that action.
  • APOTHEM_HOOKS_DISABLE=1 silences every Apothem hook, the dispatcher-routed ones and the engine install's conformity-gate hook, for troubleshooting without editing installed files.
  • Commands and skills pre-approve read-only tools only. allowed-tools names the tools a harness may run without asking while a command or skill is active. Every command declared the bare "*" wildcard, which Claude Code ignores, and 17 skills pre-approved unscoped Bash, Write, Edit, or WebFetch, so content fetched during a run could start them unprompted. Commands now declare Read, Glob, Grep, skills keep only their read-only tools, and the command and skill schemas reject "*" and bare Bash, PowerShell, Write, Edit, NotebookEdit, and WebFetch; the conformity gate enforces both schemas. Side-effecting tools still run under the operator's own permission settings.
  • /freshify, /github-deploy-fresh, and /github-deploy-next are operator-invoked only. They purge caches and history, merge, tag, and publish, so they now set disable-model-invocation: true, and the model cannot start them from its own skill choice.
  • Hook guidance no longer carries maintainer text. The license comment line and the ## Bindings section of each message file are removed before the text reaches the assistant.
  • Conformity validators report what they inspected. Every standalone report and --all result carries an inspected count. A run that inspects nothing fails unless its empty scope is declared. Unknown flags and missing files or roots exit 3.
  • The hedging check flags the filler the instruction surfaces forbid: basically, kind of as an adverb, and in some sense.
  • The always-on budget check names its unit and reports the full loaded size of the always-on rules, beside the word count it gates on.
  • The hook benchmark runs the registered hook chain on real payloads, and the agent benchmarks report "not measured" instead of passing.
  • The release SBOM describes the shipped wheel and sdist, vendored packages included, and is signed. The sdist and wheel build reproducibly with a pinned setuptools backend.
  • npm releases publish through OIDC trusted publishing only.
  • ROADMAP.md is the single roadmap, and the site page is generated from it. The release policy and runbooks describe one additive release model.
  • The repository-root plugin manifest is removed. The marketplace serves plugins/claude-code, whose manifest validates in strict mode.
  • The reference-token denylist now holds SHA-256 digests rather than the tokens. Apothem no longer ships them in readable, searchable form, but a digest of a short name can be reversed by search, and earlier releases, published npm versions and git history still carry the plaintext.
  • The release-facade rule states the additive release model. AGENTS.md, CLAUDE.md and .github/copilot-instructions.md asked for one visible release tag and one GitHub Release, while three releases stay published and npm cannot drop a version. The rule now limits what public surfaces say to the current version and keeps every published release tag, GitHub Release and npm version. The release-engineering policy and the release-recovery runbook describe the same model.

Fixed

  • The POSIX installers skip the Microsoft Store launcher. When install.sh, update.sh or uninstall.sh probes the interpreter names on PATH for Python, it now skips a match under a WindowsApps directory, the Store alias that opens the Store page instead of running Python, as the PowerShell scripts and the npm shim already did.
  • The Windows statusline runs when the interpreter path has a space. The statusline command is written unquoted, so a path such as C:\Program Files\Python314\python.exe broke at the space. Install now writes the interpreter's 8.3 short form into the statusline command when the path has a space. The hook entries keep the full path.
  • /research-spec reads the ideation it frames. Its handoff manifest said it consumed nothing, as if it were the first research stage. It now names the /research-ideate ideation, or the question or notes source the operator supplies.
  • The header check understands frontmatter and MDX. file_header_grep accepts the SPDX line after YAML frontmatter, where the injector writes it, and knows the MDX comment form. Its advisory findings fell from 808 to 7. The check stays advisory.
  • Each pre-emission bar is classified by the matchers that check it. M2 is reasoned; M5, M7, M8, M10 and M13 are mechanical; M3, M9, M12, M14 and M15 are mechanical and reasoned. The rule files, the session-start text and the docs now give the same split.
  • More documentation matches the code. A check of the pages not reviewed before corrected 88 statements on 44 pipeline, architecture, runbook, security and governance pages. The instruction files list the synced unit as the propagation manifest defines it. The Hermes page says where Hermes MCP servers are written. "Release proof" gives way to plain terms such as "gate result". The plan templates say that a typo fix in a plan is a PATCH revision, while a typo fix in an artifact leaves its version unchanged. Every translated page follows the new English text.
  • The release readiness check can pass. scripts/release/check-release-ready.sh and its PowerShell twin looked for an SPDX file the release never builds, so they could never pass. They now check the CycloneDX sbom.cdx.json the release publishes: its format, the version in its root package URL, and the vendored packages. The release runbooks document the GH_TOKEN the check needs.
  • Uninstall removes the workspace stores where install wrote them. With workspace.scope: user-home or a custom directory_name, uninstall and rollback looked for the memory/, contexts/ and learning/ stores under <root>/.apothem and left the real ones behind. Install now records the data home it resolved, and uninstall, rollback and the last-harness check use it. Installs recorded before this change keep the default location.
  • The header injector writes MDX files. scripts/inject-header.py places the SPDX line as an MDX comment after the frontmatter of an .mdx file, as the authorship-header page describes. That page now says the header check is advisory, names ADRs in plain text, and drops a header marker that nothing implements.
  • The Windows statusline command names the resolved interpreter. The Claude Code statusline's Windows command used the py -3 launcher, which not every Python install provides. It now uses the interpreter install resolves, as the hooks do.
  • "axes" is spelled correctly in the rules, commands, skills and templates that read "axs", and pre-emission bar M4 has one name, "Self-application", classified as reasoned across the rules and docs. After you upgrade, apothem diff lists the affected installed files as pending updates until the next apothem update.
  • Documentation matches the code and the maintainer's choices. A typo or link fix leaves an artifact's version unchanged. The comparison page lists durable memory and gives the synced unit as the propagation manifest defines it. The hook-event tables, the --clean note on install, the installer override text on the install page and in the README, the continuous-form alias labels, the release runbook's repository variable and the CI/CD page now say what the code does.
  • Codex hooks on Windows run the install-resolved interpreter. The commandWindows entries in hooks.json ran the py -3 launcher; they now run the CPython that install resolves, as the Claude Code hooks do, and an install with no CPython 3.10+ stops before it writes any file. Run apothem update --harness codex to re-render an existing install.
  • Shipped Markdown renders as written. A row in the Bash plan-guard hook message no longer splits on an unescaped pipe, two trace-matrix template cells and the host-discovery default marker keep their nested code spans whole, and the plan-execute resume note is no longer folded into its last option. The rule files the CodeBuddy, GitHub Copilot, Kiro, Trae, Windsurf, and Zed installs write link their vendor docs as autolinks, and Claude Code's default output style links the Apothem repository the same way. The plan-execute, plan-generate, and plan-review option lists and the projectify skill change layout only. After you upgrade, apothem diff lists these installed files as pending updates for every harness except Cursor and GLM until the next apothem update. apothem verify and apothem status still report them in sync.
  • OpenCode receives the operator profile. The projected profile document was never in the instructions list, so OpenCode saw neither the operator's identity and preferences nor the support-file locations.
  • The reference note in command skills names directories that exist. It pointed templates and hooks at a support directory no install creates.
  • The shared-root install note reads correctly when one other tool loads the path, and ~/.claude/CLAUDE.md is recorded as a Claude Code target that OpenCode also reads.
  • Hermes uninstall removes the auxiliary.mcp block an earlier release wrote, under the same exact-value rule update uses, so the operator's own auxiliary settings stay.
  • Rollback returns a harness to its exact pre-install state, and restores native configs at their real path.
  • Uninstall removes the empty directories the install created.
  • A repeat install leaves a current CRLF instruction file as it is. When the Apothem block in Claude Code's CLAUDE.md or in the projected profile document is already current, install keeps the file's bytes, CRLF line endings included, and reports it unchanged. It no longer rewrites the file with LF line endings, backs it up, and reports it updated. An instruction file that is not UTF-8 text is refused with config.unparseable and left as it is, where install and apothem diff stopped with a decoding error.
  • Operator settings survive install, update, and uninstall. Permission rules, MCP servers, Hermes auxiliary settings, and hook handlers the operator added are kept; a hook counts as Apothem's only when it runs Apothem's installed scripts.
  • Hermes MCP servers land in the top-level mcp_servers map, and an update moves the servers an earlier release wrote under auxiliary.mcp.
  • The GLM provider file is written only when absent, and GLM verifies in sync after a clean install.
  • Profile text can no longer split the managed block.
  • install --dry-run and diff list every write, and a repeated install writes nothing.
  • Cursor, Devin, and Kimi Code references point at the current vendor pages.
  • Codex keeps user-only skills out of implicit invocation. Codex ignores disable-model-invocation, so the install writes agents/openai.yaml with allow_implicit_invocation: false beside each user-only skill.
  • Claude Code skills use user-invocable, the key Claude Code reads, in the engine install and the plugin.
  • Selecting an Apothem output style keeps Claude Code's coding instructions (keep-coding-instructions: true).
  • Cursor, Kiro, Trae, CodeBuddy, and Windsurf rule files put frontmatter first, ahead of the managed-block marker, so the tool reads it. Trae rules activate with alwaysApply, and Antigravity plugin rules carry a valid trigger.
  • Converted agents keep their limits. Read-only agents run in a read-only Codex sandbox, Gemini CLI agents get a tool allowlist and max_turns, and the hard-coded Codex reasoning effort is gone. Agents no longer set memory: false, a value Claude Code does not define.
  • A missing click or rich gives a structured error naming the install command instead of a traceback, and PYTHONPATH=src resolves the vendored dependencies.
  • The one-shot installer installs and verifies in one run, and the installers emit no ANSI codes when output is not a terminal.
  • Piped output and --help epilogs keep their line structure.
  • apothem completion <shell> no longer ends the script with a blank line. The output for bash, zsh, fish, and powershell now ends in a single newline, so appending it to a shell profile adds no extra line.
  • Profiles without a version are read as version 1.
  • Qwen Code hook timeouts are written in seconds and the interpreter path is quoted.
  • The GLM provider file carries the documented model-mapping placeholders.
  • Zed installs warn when the new .rules file hides an existing instruction file, since Zed reads only the first one it finds.
  • Claude Code agent and command tool lists name the Task tools, and the settings file declares its schema.
  • Docs pages meet WCAG 2.2 AA in the checked views. Code-block and active-navigation colours reach 4.5:1 contrast, pages have main and nav landmarks, and the GitHub icon has an accessible name. Trailing-slash URLs redirect instead of returning 404, and translated pages search their own language's index.
  • Each GitHub Release attaches the VS Code extension. The README's VS Code channel installs apothem.vsix from the Release, but the release workflow never built it, and v1.1.0 carries none. The release build now packages it into the signed, hashed, and attested asset set.
  • Extension wrappers run the engine version they shipped with. The Gemini CLI and Qwen Code commands, the Gemini and Qwen Code context files, the Codex plugin skill, and the VS Code extension's default runner called npx @ahmed-g-gad/apothem with no version, so a later npm publish changed what an installed extension ran. Each call now pins the wrapper's own version, and bump_version.py moves the pins.
  • The docs describe the VS Code extension as it ships. The install page said it installs from the Visual Studio Marketplace, where no listing exists, and the README said each release attaches a signed .vsix, which v1.1.0 does not. Both now say how to install the package and how to build it from a checkout.
  • The branch protection page matches the settings on main. It described a ruleset with four required checks (ci, Scorecard, CodeQL, pip-audit), one required approval, latest-push approval, and "require branches to be up to date". main uses a classic protection rule that requires 12 checks (the ten quality cells, coverage, and Require Signed-off-by) and 0 approvals, does not bind admins, and does not require an up-to-date branch. The page now lists those exact settings and, separately, the clean-install, harness-matrix, and installer-lint checks still to be added. The solo-maintainer merge runbook, CONTRIBUTING.md, and the Scorecard page now describe the same review settings, and the runbook and admin_merge.py warn that an --admin merge also bypasses red required checks while enforce_admins is off.
  • The wheel and sdist carry the full hook corpus. They left out hooks/hooks.json and the hook READMEs that every other channel ships.
  • Path-filtered rules no longer load in every Claude Code session. Claude Code reads only paths: from a rule and loads every rule without it at launch, so the engine install loaded all 91 rules (over 900 KB) in each session. The install now writes each path-filtered rule with a paths: list built from its pathFilter; the 28 always-on rules (about 214 KB) load at launch and the 63 companions load when a matching file is read.
  • Claude Code plugin hooks run on a plain checkout. Each hook is registered once, as bash "<plugin-root>/…/bootstrap.sh" <event>, so no hook depends on a file's executable bit, and no tool call triggers the same hook twice. On Windows without Git for Windows, use the engine install, whose hooks need no shell.
  • Post-compaction recovery reaches the assistant on Claude Code. Claude Code discards PreCompact and PostCompact hook output, so those registrations did nothing there. The recovery context now arrives with the SessionStart event that follows compaction. Codex and Qwen Code keep both events.
  • Shell guards cover PowerShell and Qwen Code. The Claude Code matcher is Bash|PowerShell, and the Qwen Code matcher is ^run_shell_command$, the tool id Qwen Code reports at runtime. The engine-installed Claude Code settings also deny the PowerShell forms of git push --force, git push --force-with-lease, git push -f, and Invoke-Expression.
  • The dependency and dynamic-eval guards speak only when relevant. They fired on every write and every shell call. The dependency guard now needs a write to a dependency manifest or lockfile, and the eval guard needs an evaluation or unsafe-deserialization primitive in the content or command.
  • The strict AskUserQuestion guard blocks through the current channel. It returns permissionDecision: deny with a reason, which Claude Code honors, instead of the deprecated top-level decision field.
  • Session-start memory lookup finds the project's memory index. It keys on the project directory from the harness, ascends a payload working directory to its Git root, and honors CLAUDE_CONFIG_DIR. The plugin-alone pointer prints the resolved rules path instead of an unexpanded variable.
  • The engine-installed conformity gate hook starts. It failed to import its package in the installed layout and crashed on every write.
  • Several validators no longer pass while inspecting nothing, including the naming check and the five-direction Bindings check, and the secret-leak check no longer flags AWS documentation example keys.
  • The profile loader returns structured errors for invalid UTF-8, YAML alias cycles, and very deep nesting instead of raising.
  • The documented release verification passes on real release assets, with the exact signer identity, and the verifier script checks all three layers.
  • Distribution metadata declares MIT AND PSF-2.0, and REUSE attributes the plugin tree's vendored code to its authors.
  • SECURITY.md lists 1.1.x as supported, the release badge reads the tag from full history, and the CHANGELOG links resolve.
  • install.sh and update.sh treat only vMAJOR.MINOR.PATCH tags as release tags, as install.ps1 and update.ps1 do. Both scripts matched v1.2.3.4, v1..2.3, and v1.2.3v, and update.sh also matched v1.2.3-rc1 and v1x.2.3. A ref pinned to one of these went to git verify-tag instead of stopping as "not a signed release tag", and install.sh accepted the first three for APOTHEM_VERIFY=checksum. Both scripts now use the same check.
  • install.ps1 and update.ps1 match release tags case-sensitively, as install.sh and update.sh do. Test-ReleaseTag used -match, which ignores case, so the PowerShell scripts took V1.2.3 for a release tag. A ref pinned to V1.2.3 went to git verify-tag instead of stopping as "not a signed release tag", and install.ps1 accepted it for APOTHEM_VERIFY=checksum. Test-ReleaseTag now uses -cmatch.
  • install.ps1 and update.ps1 reject a ref that ends in a newline, as install.sh and update.sh do. Test-ReleaseTag ended its regex with $, which in .NET also matches before a final newline, so it took v1.2.3 followed by a newline for a release tag. A ref read with Get-Content -Raw keeps that newline. With APOTHEM_VERIFY=checksum, install.ps1 then tried to download a release archive for that ref instead of stopping with "needs a vMAJOR.MINOR.PATCH release tag". In signature mode, git checkout already refused the ref on every platform before the check ran. Test-ReleaseTag now ends with \z, which matches only at the end of the string.
  • check-release-ready.ps1 checks the tag as check-release-ready.sh does. It used -notmatch with a regex ending in $, so it accepted V1.2.3 and v1.2.3 followed by a newline, which the Bash script rejects. It now uses -cnotmatch and \z.
  • install.ps1 and update.ps1 pick the latest release tag case-sensitively, as install.sh and update.sh do. With APOTHEM_REF unset, Resolve-LatestTag filtered git ls-remote output with -match, which ignores case, so a V9.9.9 tag above the newest vX.Y.Z release became the default ref. Test-ReleaseTag then rejected it, so the run stopped as "not a signed release tag", or with "needs a vMAJOR.MINOR.PATCH release tag" under APOTHEM_VERIFY=checksum. With APOTHEM_ALLOW_UNVERIFIED=1, it went on with that tag's tree. The POSIX scripts skip such a tag and take the newest release. Resolve-LatestTag now uses -cmatch.
  • install.ps1 and update.ps1 resolve a remote's only release tag. With APOTHEM_REF unset and one vX.Y.Z tag on the remote, Resolve-LatestTag returned the tag's last character, such as 0 for v1.1.0. A pipeline that emits one string yields that string, not an array, and indexing a string returns a character. The run then stopped with "Could not check out 0", or with "needs a vMAJOR.MINOR.PATCH release tag" under APOTHEM_VERIFY=checksum. install.sh and update.sh resolve the tag. Resolve-LatestTag now wraps the sorted tags in @().
  • The installers give key-import guidance in any language. When the maintainer key was missing from the local keyring and GnuPG printed its messages in another language, install.sh, install.ps1 and update.sh reported the signed tag as possibly tampered with, because they matched GnuPG's English text. They now read GnuPG's status lines ([GNUPG:] NO_PUBKEY), which do not change with the language.
  • The shell rules' PowerShell lint command reports syntax errors. The code-craft-shell and performance-discipline rules ran Invoke-ScriptAnalyzer -Severity Error,Warning. PSScriptAnalyzer reports a syntax error at severity ParseError, and an explicit -Severity list without it drops the error, so a script that did not parse passed clean. Both rules now pass -Severity Error,Warning,ParseError.
  • The shell rules' PowerShell lint check fails on a finding. The code-craft-shell rule said Invoke-ScriptAnalyzer ... "exits 0" and that the host's PSScriptAnalyzerSettings.psd1 "is honored". Without -EnableExit the cmdlet exits 0 even when it reports findings, and without -Settings it reads a settings file only from the -Path folder, never a parent folder. The rule now passes when the analyzer returns no records, runs a command that exits 1 on any record, and passes -Settings when the host has a settings file. The command also exits 1 when the script, the settings file or the PSScriptAnalyzer module is missing, under both pwsh -Command and pwsh -File. The performance-discipline §1.1 verifier exits 1 on any record in the same way.
  • update.ps1 checks a release tag's signature the way update.sh does. A signed tag whose maintainer key is missing from the local keyring now aborts with key-import guidance instead of being reported as unsigned, and an unsigned or tampered tag aborts without suggesting APOTHEM_ALLOW_UNVERIFIED=1. Under Windows PowerShell 5.1, which update.bat runs, the check no longer stops the update on GnuPG's output, which it did even for a validly signed tag.
  • install.ps1 can verify a release tag under Windows PowerShell 5.1. Under Windows PowerShell 5.1, which install.bat runs, the signature check stopped the install on GnuPG's first output line, even for a validly signed tag, so an install that clones a release could not finish. The check now gives the same result as on PowerShell 7.2 and later: a valid signature passes, a missing maintainer key gets key-import guidance, and an unsigned or tampered tag aborts.
  • Translated release and security pages match their English pages again. In all eleven translations, the release-recovery runbook still told readers to reset main to a safety tag, force-push it, and delete a malformed release and its tag. The English runbook and the release-engineering policy forbid all three: main is never force-pushed, and no published tag, GitHub Release or npm version is deleted, moved or reused. The translated policy also lacked its "Release model: additive" subsection, and the translated branch-protection page listed settings that are not live. Those three pages, the release-cycle, solo-maintainer merge and publisher-account runbooks, the runbooks index, the Scorecard posture page and the security index are translated again from their current English text in every language, and the site no longer marks them out of date.
  • Every translated docs page matches its English page again. The other 66 pages in each language, 726 in all, were translations of older English text. For example, the translated quickstart said apothem doctor fails when a harness is not installed, where it now lists that harness and passes, and the translated installer-variables page lacked APOTHEM_VERIFY, APOTHEM_RELEASE_BASE and NO_COLOR. These pages are translated again from their current English text in all eleven languages, and no page is marked out of date. Links to a section of a translated page now reach that section: they had pointed at English heading names the translated pages do not use. The translated source-layout, conformity-gate and pipeline pages now show the generated tables their English pages carry.
  • Install runs under a Microsoft Store Python. The interpreter resolver rejected the Python that was running it whenever its path contained WindowsApps, which is the path the Store build of CPython reports for itself. So apothem install, update and diff for Claude Code and Qwen Code stopped with a traceback ending in no real CPython >= 3.10 interpreter found. The resolver now uses that interpreter as it reports itself. Its search of PATH still skips the Store launcher stub.
  • English docs pages state what the code does. Translators of the docs reported 44 statements that could lead a reader to act wrongly. Seven had been corrected already; the other 37 are fixed on 33 pages. For example, APOTHEM_PYTHON is tried first and the npm shim falls back to python3, python and py -3 when it fails, so it does not skip the probe. apothem diff rejects all. apothem rollback fails with rollback.no_record for a harness with no recorded install and carries on with the others. apothem update --harness glm writes glm.toml only when the file is missing. Eight light-mode brand colors fall below WCAG AA against white text, and no dark-mode color reaches it. publish-npm.yml runs on the tag push, with manual dispatch as the fallback. The conformity-gate pages call M2 reasoned and M3, M12 and M15 part mechanical, and say the semver-stability validator runs on its own, not through the gate. The uninstall page now covers the VS Code-family extension, the command-line bootstraps and the direct engine.
  • Docs pages say what each uninstall removes, and fix 132 more statements. Translators of two further rounds sent 570 reports, which merge into 171 distinct statements. Each was checked against the code. 113 are fixed, 50 read two ways but lead no reader to act wrongly, so their wording stays, 3 were already correct, and 5 wait on a maintainer decision. Checking turned up 19 more, all fixed, so 132 statements are corrected on 55 pages. Uninstall no longer "removes the native config files" on every harness page: each page says what is removed, what stays and what is backed up under ~/.apothem/backups/ first. Adapters that merge into a shared file strip only their managed block or their own keys. Uninstalling the last harness at an install root also backs up and removes the memory/, contexts/ and learning/ stores, and never touches plans/. apothem verify takes --harness all, the installers write the apothem shim into a directory and never edit PATH, and the npm shim and the installers probe for Python with different lists. The cognitive-identity page says Filters 1 and 5 always run and Filters 2 to 4 apply to non-trivial decisions. CI does not run markdownlint. These pages are translated again from their current English text in all eleven languages.

Security

  • The release build tooling uses urllib3 2.8.0, which fixes PYSEC-2026-4175, PYSEC-2026-4176 and PYSEC-2026-4177 in the hash-locked tooling the release workflow installs before it builds.
  • Profile text cannot carry the managed-block markers. A profile value containing a block marker fails validation with profile.managed_block_marker, naming the field without echoing the value.
  • The VS Code extension runs only a user-scoped runner, quoted, for a chosen harness; a workspace setting can no longer set the command it runs.
  • The release packages the VS Code extension in a job of its own. vsce installs from a committed lockfile with npm ci --ignore-scripts, in a job that never sees the Python distributions, and only apothem.vsix passes to the build job, which adds it to the dist/ assets that are hashed, signed and attested. Before, npx resolved the packager's dependency tree at release time, with install scripts, in the job that built the wheel. The Marketplace workflow uses the same lockfile. The packager is vsce 4.0.0, which no longer pulls in braces 3.0.3 (GHSA-vfj7-8cjw-p6xm, with no patched release).
  • No long-lived npm token path remains. The npm publish workflow authenticates through OIDC alone; the token secret and its opt-in gate are gone.
  • Hooks never run code from the opened project. The bootstrap stubs resolve the dispatcher from their own installed location. Previously the stubs took their root from the project directory when it contained a hooks/ folder, so a project could supply the interpreter locator or the dispatcher that the plugin's hooks then ran. Session-start guidance is read from the installed tree; the project is read only for plan and memory summaries.
  • Per-session hook state is private to the user. The session-end gate and the compaction tracker kept counters in a shared directory under the system temp dir, created with default permissions. State now lives in a per-user directory created with mode 0700, and session ids are sanitized before use as file names. APOTHEM_HOOK_STATE_DIR overrides the location.

1.1.0 - 2026-08-16

Fixed

  • status and verify no longer swallow a profile that fails to load. status hardcoded an empty warnings array and printed nothing in plain mode; with nothing installed there was no unknown drift cell either, so the failure left no trace at all. verify --harness all discarded the failure to read its exclusions, so excluded harnesses rejoined the sweep and the run died later on a missing project path that named them — with no sign of the real cause. Both now surface a structured advisory naming the diagnostic code and the fix.
  • The PowerShell interpreter locator no longer throws where its contract promises $null. find-pwsh.ps1 built its Windows install-root fallbacks with an unguarded Join-Path $env:ProgramFiles, which is unset under PowerShell on Linux and macOS. The list was built eagerly, so the throw pre-empted even the PATH probe that would have succeeded.
  • migrate-workspace reports a legacy data home it failed to remove. The removal ignored errors, so when a locked file or a denied permission kept the directory on disk, the command still reported a clean migration and the next run found the same directory again. It now adds a note that names the directory: its records are already merged into the shared store and kept in the backup, so the directory can be deleted by hand.
  • Documentation corrections across the conformity gate's hook scope, the design tokens' consumers, the OpenCode example's provenance, two harness convention pins, and four architecture pages that were unreachable from ten locale indexes.

1.0.2 - 2026-08-14

Fixed

  • The Stop hook no longer re-asserts the session-end protocol on every turn. Stop fires at the end of every assistant turn, not only at the end of a session, and the hook emitted hooks/messages/stop.md verbatim each time. Because that body reads as a fresh work order rather than a status check, every response triggered another firing and nothing the agent did changed what the hook asserted — the loop had no fixed point, and an operator could only escape it by restarting the harness, since hook configuration and message bodies are both snapshotted at session start. A new dispatch-routed handler, hooks/session_end_gate.py, supplies the missing termination condition: the protocol is emitted at most once per session, and only once the session has accumulated enough turn-ends to have state worth externalizing. The message file still owns the protocol text — the gate decides only when it is emitted — so its path and its cross-references from rules/context-management.md and rules/auto-memory.md are unchanged. Two environment variables tune it: APOTHEM_SESSION_END_MIN_STOPS (default 3) sets the firing floor, and APOTHEM_SESSION_END_ENABLED=0 silences the protocol entirely without editing installed plugin files.
  • The detection pseudocode in the canonical option-shapes rule is fenced as text rather than Python. The block uses the hyphenated schema field names the same document defines in its field table, which are not valid Python. Correcting the fence language leaves the pseudocode byte-identical.

1.0.1 - 2026-07-07

Apothem is a host-agnostic AI-harness configuration manager: one governed shared profile materializes into the native configuration of seventeen assistant harnesses behind a conformity governance gate and signed, reproducible releases.

Added

  • Shared-profile model. One governed profile at ~/.config/apothem/profile.yaml is the single source for the synced unit — rules, slash-commands, skills, hooks, output-styles, settings, schemas, docs, and MCP servers — plus the wrapped-workflow orchestrators that drive whole missions end to end (/plan, /research, /audit, and the /fortress closed-loop production-hardening pipeline).
  • Seventeen harness adapters. Antigravity, Claude Code, CodeBuddy, Codex, Cursor, Gemini CLI, GitHub Copilot, Hermes, Kimi Code, Kiro, Open-Claw, OpenCode, Qwen Code, Trae, Windsurf, Zed, and GLM (Z.ai) each install, verify, update, and uninstall through a shared, reversible adapter contract that emits the tool's native file layout. Installs back up existing targets before replacement; uninstalls reverse cleanly with zero orphans.
  • CLI. quickstart, install, uninstall, update, verify, status, diff, rollback, migrate-workspace, harnesses, profile, doctor, and completion, with dry-run reporting, drift detection, and structured JSON output (--format json). The engine is self-contained — the source tree carries its vendored dependencies and runs from a checkout as python -m apothem on system Python 3.10+.
  • Conformity governance gate. A pre-emission validator suite checks the synced unit — authorship headers, frontmatter contracts, naming, determinism, cross-references, and harness capability coverage, including a cross-file binding-reciprocity validator that keeps every rule cross-binding closed at its cited peer — before any surface is materialized.
  • Install paths. The Claude Code plugin (/plugin marketplace add ahmed-g-gad/apothem), a Gemini CLI extension, a Qwen Code extension, a Codex plugin, the npm shim (npx @ahmed-g-gad/apothem <command>), and the one-shot POSIX and PowerShell installers (install.sh / install.ps1) with matching update and uninstall scripts. The source of a VS Code-family extension is in vscode-extension/; this release attaches no packaged .vsix, and the extension is not listed on the Visual Studio Marketplace.

Changed

  • Unified install layout. Materialized machinery (hooks, the conformity gate, schemas, templates) and non-native cohorts (rules, skills, agents) install under a single Apothem-owned .apothem/support/ tree inside each harness's configuration root, so each profile carries one Apothem-owned dotted directory rather than two similarly-named siblings.
  • Leaner always-on rules tier. The always-loaded behavioral rules were consolidated to twenty-eight, with situational depth moved into demand-loaded companion rules, so a session — or a fleet of sub-agents — ingests fewer tokens up front while every discipline still fires where it applies.

Security

  • Every release attaches an sdist, a wheel, SHA-256 checksums, Sigstore cosign signatures, SLSA build provenance, and a CycloneDX SBOM as verification evidence; the npm package publishes with Sigstore build provenance signed from the GitHub Actions OIDC identity, and a conformity validator holds every release workflow to a provenance-signed, pinned publish path.
  • The pipeline gates every change on lint, tests, type checks, a documentation build, CodeQL, OpenSSF Scorecard, dependency review, a scheduled OSV vulnerability scan, and supply-chain checks before publication. The one-shot installers pin their click / rich prerequisites to the engine's declared constraints and document an inspect-first alternative to the pipe-to-shell one-liner.

On this page