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 runsvsce 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 thereleaseenvironment. The job first checks that the vsce release locked intools/vscesupports the final token exchange, and stops with a plain error when it does not. The Entra route and theVSCE_PATtoken stay as alternatives. An unrecognisedVSCE_AUTHvalue 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/vscelockfile 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/vscenow packages the VS Code extension and runs the vsce release tests, and one that changestools/channel-smokeruns the channel smoke, so a Dependabot update to either lockfile is checked before it merges. The pull request runs these checks without the fullci.ymlmatrix. - CI installs pip from a hash-locked file. Every workflow upgrades pip
with
--require-hashesfromscripts/ci/requirements-ci-pip.txtinstead 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.pynow checks the lock file and the workflows' install lines instead of the per-workflow version setting, andpip-audit.ymlaudits 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-hasheswithscripts/ci/requirements-ci-dev.txt,requirements-ci-runtime.txt,requirements-ci-test.txtorrequirements-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.pyregenerates the locks, and--checkcompares them with a fresh compile.tests/scripts/test_ci_locks_fresh.pyfails when a lock no longer satisfiespyproject.toml.pip-audit.ymlstill resolves the newest allowed versions each week and now audits the locks too,check_pip_pin_drift.pyfails on any other workflowpip installthat Scorecard counts as unpinned, and Dependabot's version updates forscripts/ciare limited to the pip lock. - The CI tools install from hash-locked files.
ruff,bandit,pip-audit,pip-licensesandpre-commitno longer install as exact version pins. Each installs with--require-hashesfrom its own file inscripts/ci/(requirements-ci-ruff.txt,-bandit.txt,-pip-audit.txt,-pip-licenses.txtand-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, inscripts/dev/ci_lock_table.py, andcheck_pip_pin_drift.pynow fails on any unhashed tool install. The pip-audit lock leaves pip out, andrefresh_ci_locks.pynow excludes pip from every lock, because a second pip pin would replace the one inrequirements-ci-pip.txtthat Dependabot maintains. The pre-commit lock needs Python 3.11, whichmarkdown-lint.ymlalready uses. The pip-audit lock is compiled for Python 3.11 too: the newestfilelockthat 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.ymlaudits 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 againstvirtualenv21.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 bypip-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.tomlnamed a floor, and theruff-pre-commithook, 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.pyfails 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. Theruff-formatpre-commit hook now also formats Markdown files, because ruff 0.17 formats the Python code blocks in them and CI'sruff 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.pylocks the files uploaded before the lock date less seven days,--cooldown-days Nchanges that, and--cooldown-days 0locks 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 ofscripts/dev/ci_lock_table.pycan lift it for one package withcooldown_exceptions: the pre-commit lock takesvirtualenv21.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--checkreproduces 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.1to 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 in0.0.0.0/8or::, is now reported asunroutableand 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/vsceand.github/channel-smoketotools/vsceandtools/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.ymlruns the Scorecard action withfile_mode: git, so Scorecard reads a clone of the repository. It read a GitHub archive ofmain, which leaves out.github/apart fromdependabot.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.pyfails when a translation's index differs from the English one.
Security
- The VS Code packaging tool's lockfile takes the
minimatchfix. The lockedvscetoolchain (tools/vsce) moves its transitiveminimatchfrom 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 requireminimatch10.x, which has no fixed release, sotools/vsce/package.jsonoverrides 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.vscodeignoreat 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 onSessionStartand the context-size advisory onPostToolUse. For Cursor it adds onesessionStartentry, 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 forPreToolUse, 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.jsonis your file and Cursor documents project hooks as committed, so the install adds its entry after yours, keeps your entries and keys, reportsconfig.unparseableand 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'sread_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 fromDEVIN_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.pywith--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 runspython -m apothem.conformity.gate, is never replaced or removed;apothem verifyfails 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 onSessionStartand the context-size advisory onPostToolUse. The scripts go in.apothem/support/hooks/. CodeBuddy hands extra context to the model for those events and documents none forPreToolUse, 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 committedsettings.json. CodeBuddy does not run hooks another tool wrote until you restart it and review them in its/hookspanel, 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.jsonfor Kiro (the session bootstrap onSessionStart) and.github/hooks/apothem.jsonfor Copilot (the session bootstrap onsessionStartand the context-size advisory onpostToolUse), 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 frompreToolUse. 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 thebashcommand 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 toapothem.jsonstays, and an uninstall removes only the hooks that run the Apothem dispatcher. A Kiro hook you switch off with"enabled": falsestays 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.mdfor GitHub Copilot and in.cursor/agents/as<name>.mdfor 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 markedreadonly: 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 (WebFetchbecomesFetchURL,TodoWritebecomesTodoList, 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 lowercaseallowed-toolslist, andBashbecomesexec. Windsurf gets eleven of the fourteen helpers: Devin documents no tool name for web search or web fetch, socitation-auditor,fact-checkerandresearch-scoutwait until it does. No model is set for either tool, and Kimi Code never getsoverride. 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.ymlnow picks its credential in aSelect Marketplace credentialstep. With the repository variablesVSCODE_MARKETPLACE_READY=true,VSCE_AUTH=entra,AZURE_CLIENT_IDandAZURE_TENANT_IDset, the job signs in through a GitHub OIDC federated credential (Azure/login, pinned by commit, no client secret) andvsce publish --azure-credentialpublishes with a short-lived token; the Entra steps never receiveVSCE_PAT. Without those variables theVSCE_PATsecret publishes as before, and the credential is a switch, not an automatic retry. WhenVSCE_AUTH=entrais set but the client or tenant id is empty, the run logs a warning whether or notVSCE_PATis set. The two switch variables are compared without regard to case. On the Entra route, a manual dispatch with the newdry_runinput signs in and verifies publisher access without publishing; on the token route it warns that nothing was verified. The publish job now holdsid-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/nodemoves from 25 to 22, the major of the site's Node floor (enginesand.nvmrc), so the type-check no longer accepts Node APIs that Node 22 lacks. Dependabot stops proposing@types/nodemajor updates for the site; raise that major together with the floor.
Fixed
- The licensing gate runs on every change.
reuse lintran 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.ymlnow 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>anddironly 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), soagnosticism-grepfailed the strict gate on theAGENTS.mdcopies inside a worktree, and the same walk enteredsite/node_modules, which stretched a strict run past ten minutes. One shared tree walk in_grep_base.pynow skips any directory that holds a.gitfile or directory, plus the vendored, virtual-environment, cache and build-output trees (node_modules,_vendor,venv,dist,.nextand similar), wherever they sit.agnosticism-grep,agents-md-coverage-grep,dynamism-grep,freshness-token-grep,plain-language-grepandreference-token-grepuse it; the stray-suite sweep inno-global-plans-grepkeeps its own walk and now also stops at a nested checkout. Validators that read one fixed folder, such asnaming-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-grepandreference-token-grepnow list their findings in directory order instead of one pass per file suffix.
Security
- The VS Code packaging tool's lockfile takes the
qsfix. The lockedvscetoolchain (.github/vsce) moves its transitiveqsfrom 6.16.0 to 6.16.1, which fixes GHSA-6pq8-jhm2-2vcw (an uncaught error inqs.stringifywith 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_serverskey now also reaches the Gemini CLI install: for each listed helper, itstoolsallowlist gains onemcp_<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 owndisallowedToolsnames 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).
- design fixes the experimental unit, allocation and its concealment,
masking, nuisance factors and run order, control conditions, and within-unit
and multi-factor structure (
- Reference entries from identifiers.
paper-toolkitgains anentriesmode: 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.ymlnow 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.jsonis 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..gitattributeskeeps.github/dependabot.ymlin 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.ymlcarries 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 addcloned 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.tomlonly 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.tomlrecords the digests of the templates fromv1.0.1throughv1.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-wikigrows 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-matrixchooses between options with weighted, evidence-cited scores, dealbreakers first and a check that the winner survives weight changes;issue-lifecycletakes 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-designdesigns and refines interfaces to a craft floor with aDESIGN.mdproject context. - Two read-only subagents.
citation-auditorverifies references and whether each cited source says what it is cited for;design-criticreviews 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-provenanceasks research files to label how each claim's evidence was read and keep a search record;code-craft-uicarries 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-toolkitwrites 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.perspectivesruns several separate viewpoints on a contested question, then reconciles them into agreement, real disagreements, a recommendation with its confidence and the strongest dissent.teaching-packturns 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 --paperreviews 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-assuranceasks 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-publishdrafts 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-grepis 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-lifecyclecan draft a request to the reporter for missing details and, only when you name thepublishstage, open a draft pull request after three separate confirmations.citation-auditorandresearch-scoutuse 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
## Bindingscross-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-rotationandissue-lifecycle) run only when you invoke them.plan-suiteandresearch-suiteare 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 --checkkeeps 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.extraDirsand Hermes'sskills.external_dirs, after any entries you already have; uninstall removes only that entry, andverifychecks 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 commentedopenclaw.jsonorconfig.yamlthat lacks the entry is refused with the line to add, as for OpenCode and Qwen Code. -
research-scoutandcitation-auditorkeep a read-only tool list and reach a scholarly lookup server only when you name it. Theirtoolslist staysRead, 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 onemcp__<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
allowedToolsas a list, the key and shape Qwen Code reads; it ignoresallowed-toolsand 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
nullcounts 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 inplugin.jsonat its root, the format Codex documents for new packages, and keeps.codex-plugin/plugin.jsonas the documented fallback. The marketplace entry carries thepolicyblock 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.mdof at most about 5,000 tokens with the procedure the model needs every time, plusreferences/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-executewere lost before. Commands are still invoked as/apothem:<name>; other harnesses are unchanged. Extra frontmatter keys now sit undermetadata. -
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
## Advisorysection 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_TOKENSto 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.pyrebuilds every raster from its source. -
make lintalso runsmypy. The target now matches the lint gate the docs describe:ruff check,ruff format --checkand strictmypy. -
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 whenCODEX_HOMEpoints 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.ymland theFundingURL inpyproject.tomlare 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.tomltemplate 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 uneditedglm.tomlwritten 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
evalorcompileare skipped, a shellevalmust start a statement and expand something, and a command that only searches or commits is not scanned.yaml.loadwith aSafeLoaderanywhere 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
lsandmkdir; it now classifies the targets of redirects,tee,touch, the destination ofcp,mvandinstall, 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_patchwrites 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, andUTF-8,SHA-256,ISO-8601,CVE-…andRFC-…no longer read as plan identifiers. -
/.well-known/security.txtis 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'sExpiresmatches the root copy. -
The docs match the code again. Install examples for project-scope harnesses name the project, the
verifyanddoctorpages describe what the commands do,TRANSLATING.mddescribes 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
certifi2026.10.19 (PYSEC-2026-4320, a distrusted root certificate) andsetuptools84.1.0 (GHSA-xmj3-9gf7-h52w, a legacy wheel-install path), andbuild-system.requirespins the samesetuptools. Neither advisory reaches an Apothem install: the setuptools path is reached only through the deprecatedsetup_requiresmechanism, which Apothem does not use, and the build environment'scertifiis not shipped. - Documentation site dependencies updated for three advisories. The site
moves to
next16.4.3 (GHSA-2464-fhr4-w9xw, GHSA-p3m5-59mp-jv5r, GHSA-673q-mjm6-r5xr) andzod4.6.7 (GHSA-mrhx-c7xc-m3w5). None reaches the published site: it is a static export with unoptimized images, no server actions and nouse cachefunctions, andzodvalidates page frontmatter only at build time. - VS Code publishing tool updated for one advisory. The locked
vscetoolchain overrides@azure/msal-nodeto 7.1.1 (GHSA-xcx6-jx8p-x3h5), since@azure/identitystill 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 withcode --install-extension ahmed-g-gad.apothem-vscode; the signedapothem.vsixattached 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 nameapothem, so the extension takes a new one. A copy installed from an earlierapothem.vsixkeeps the identifierahmed-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.shandverify-provenance.ps1checked the release assets namedapothem-*, which left outapothem.vsixand 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
releaseenvironment: the GitHub Release publish first, then npm and the VS Code extension oncecheck-release-ready.shpasses. The publisher-account runbook approves the GitHub Release publish before it runs the check, too.
1.2.1 - 2026-10-19
Changed
/plan-auditruns 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,--remediateand--maintenance, which the command never defined;--cap Nand--dry-runremain.- 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.mdlists 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.mddid not publish.SECURITY.mdnow 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 ownbash, whose keyringgit verify-tagreads), 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-publishand/security-auditnow state the gates, outputs and options their commands have. The CLI reference covers how--harness alltreatsexclude_harnesses, every token prefix the MCP warning flags, what a dry run reports, and that--verboseadds nothing todoctoranduninstall. 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-placerewrote 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_fetchtool 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/, andconformity/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 pruneruns 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=checksuminstalls the release's platform archive after checking its SHA-256 against the release'sSHA256SUMS, 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 toAPOTHEM_ALLOW_UNVERIFIED=1for a host without the maintainer's public key. - Every
--jsonobject carriesschema_version, and the profile schemas are served at their$idURLs.harnesses list --jsonstays a JSON array, so it has no top-level key to carry the version. doctorprobes 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, plainhttp://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.ymlruns 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 inscripts/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 --consentinstalls 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/auditstage, and paired rule-effect cases.evals/case.schema.jsonand a test validate every case, and a manual-dispatch, cost-capped Evals workflow runs them on demand. - CI records per-commit metrics. A
metricsjob runsscripts/dev/collect_metrics.pyand 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.pymoves 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-grepvalidator 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.jsoninstructionslists the profile document and the 28alwaysApplyrules 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 owninstructionsentries 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, andconfigure_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_lossesmap in itscapabilities.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.usageenvelope under--json, distinct from a findings or partial-write exit. quickstartasks for a harness instead of configuring all seventeen;--harness allkeeps the old behaviour. The firstinstallcreates the default profile.doctorjudges 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.mdblock and the Gemini CLI and AntigravityGEMINI.mdblocks 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
Stophook 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. SetAPOTHEM_SESSION_END_ENABLED=1to 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.
/planand/researchtake--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=1silences 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-toolsnames 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 unscopedBash,Write,Edit, orWebFetch, so content fetched during a run could start them unprompted. Commands now declareRead, Glob, Grep, skills keep only their read-only tools, and the command and skill schemas reject"*"and bareBash,PowerShell,Write,Edit,NotebookEdit, andWebFetch; 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-nextare operator-invoked only. They purge caches and history, merge, tag, and publish, so they now setdisable-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
## Bindingssection of each message file are removed before the text reaches the assistant. - Conformity validators report what they inspected. Every standalone
report and
--allresult carries aninspectedcount. 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 ofas an adverb, andin 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.mdis 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.mdand.github/copilot-instructions.mdasked 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.shoruninstall.shprobes the interpreter names onPATHfor Python, it now skips a match under aWindowsAppsdirectory, 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.exebroke 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-specreads the ideation it frames. Its handoff manifest said it consumed nothing, as if it were the first research stage. It now names the/research-ideateideation, or the question or notes source the operator supplies.- The header check understands frontmatter and MDX.
file_header_grepaccepts 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.shand its PowerShell twin looked for an SPDX file the release never builds, so they could never pass. They now check the CycloneDXsbom.cdx.jsonthe release publishes: its format, the version in its root package URL, and the vendored packages. The release runbooks document theGH_TOKENthe check needs. - Uninstall removes the workspace stores where install wrote them. With
workspace.scope: user-homeor a customdirectory_name, uninstall and rollback looked for thememory/,contexts/andlearning/stores under<root>/.apothemand 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.pyplaces the SPDX line as an MDX comment after the frontmatter of an.mdxfile, 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 -3launcher, 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 difflists the affected installed files as pending updates until the nextapothem 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
--cleannote oninstall, 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
commandWindowsentries inhooks.jsonran thepy -3launcher; 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. Runapothem update --harness codexto 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-executeresume 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. Theplan-execute,plan-generate, andplan-reviewoption lists and theprojectifyskill change layout only. After you upgrade,apothem difflists these installed files as pending updates for every harness except Cursor and GLM until the nextapothem update.apothem verifyandapothem statusstill report them in sync. - OpenCode receives the operator profile. The projected profile document
was never in the
instructionslist, 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.mdis recorded as a Claude Code target that OpenCode also reads. - Hermes uninstall removes the
auxiliary.mcpblock an earlier release wrote, under the same exact-value ruleupdateuses, so the operator's ownauxiliarysettings 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.mdor 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 withconfig.unparseableand left as it is, where install andapothem diffstopped with a decoding error. - Operator settings survive install, update, and uninstall. Permission
rules, MCP servers, Hermes
auxiliarysettings, 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_serversmap, and an update moves the servers an earlier release wrote underauxiliary.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-runanddifflist 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 writesagents/openai.yamlwithallow_implicit_invocation: falsebeside 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 validtrigger. - 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 setmemory: false, a value Claude Code does not define. - A missing
clickorrichgives a structured error naming the install command instead of a traceback, andPYTHONPATH=srcresolves 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
--helpepilogs keep their line structure. apothem completion <shell>no longer ends the script with a blank line. The output forbash,zsh,fish, andpowershellnow 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
.rulesfile 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
mainandnavlandmarks, 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.vsixfrom 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/apothemwith no version, so a later npm publish changed what an installed extension ran. Each call now pins the wrapper's own version, andbump_version.pymoves 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".mainuses a classic protection rule that requires 12 checks (the tenqualitycells,coverage, andRequire 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 andadmin_merge.pywarn that an--adminmerge also bypasses red required checks whileenforce_adminsis off. - The wheel and sdist carry the full hook corpus. They left out
hooks/hooks.jsonand 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 apaths:list built from itspathFilter; 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 ofgit push --force,git push --force-with-lease,git push -f, andInvoke-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: denywith a reason, which Claude Code honors, instead of the deprecated top-leveldecisionfield. - 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.shandupdate.shtreat onlyvMAJOR.MINOR.PATCHtags as release tags, asinstall.ps1andupdate.ps1do. Both scripts matchedv1.2.3.4,v1..2.3, andv1.2.3v, andupdate.shalso matchedv1.2.3-rc1andv1x.2.3. A ref pinned to one of these went togit verify-taginstead of stopping as "not a signed release tag", andinstall.shaccepted the first three forAPOTHEM_VERIFY=checksum. Both scripts now use the same check.install.ps1andupdate.ps1match release tags case-sensitively, asinstall.shandupdate.shdo.Test-ReleaseTagused-match, which ignores case, so the PowerShell scripts tookV1.2.3for a release tag. A ref pinned toV1.2.3went togit verify-taginstead of stopping as "not a signed release tag", andinstall.ps1accepted it forAPOTHEM_VERIFY=checksum.Test-ReleaseTagnow uses-cmatch.install.ps1andupdate.ps1reject a ref that ends in a newline, asinstall.shandupdate.shdo.Test-ReleaseTagended its regex with$, which in .NET also matches before a final newline, so it tookv1.2.3followed by a newline for a release tag. A ref read withGet-Content -Rawkeeps that newline. WithAPOTHEM_VERIFY=checksum,install.ps1then tried to download a release archive for that ref instead of stopping with "needs a vMAJOR.MINOR.PATCH release tag". In signature mode,git checkoutalready refused the ref on every platform before the check ran.Test-ReleaseTagnow ends with\z, which matches only at the end of the string.check-release-ready.ps1checks the tag ascheck-release-ready.shdoes. It used-notmatchwith a regex ending in$, so it acceptedV1.2.3andv1.2.3followed by a newline, which the Bash script rejects. It now uses-cnotmatchand\z.install.ps1andupdate.ps1pick the latest release tag case-sensitively, asinstall.shandupdate.shdo. WithAPOTHEM_REFunset,Resolve-LatestTagfilteredgit ls-remoteoutput with-match, which ignores case, so aV9.9.9tag above the newestvX.Y.Zrelease became the default ref.Test-ReleaseTagthen rejected it, so the run stopped as "not a signed release tag", or with "needs a vMAJOR.MINOR.PATCH release tag" underAPOTHEM_VERIFY=checksum. WithAPOTHEM_ALLOW_UNVERIFIED=1, it went on with that tag's tree. The POSIX scripts skip such a tag and take the newest release.Resolve-LatestTagnow uses-cmatch.install.ps1andupdate.ps1resolve a remote's only release tag. WithAPOTHEM_REFunset and onevX.Y.Ztag on the remote,Resolve-LatestTagreturned the tag's last character, such as0forv1.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" underAPOTHEM_VERIFY=checksum.install.shandupdate.shresolve the tag.Resolve-LatestTagnow 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.ps1andupdate.shreported 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-shellandperformance-disciplinerules ranInvoke-ScriptAnalyzer -Severity Error,Warning. PSScriptAnalyzer reports a syntax error at severityParseError, and an explicit-Severitylist 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-shellrule saidInvoke-ScriptAnalyzer ..."exits 0" and that the host'sPSScriptAnalyzerSettings.psd1"is honored". Without-EnableExitthe cmdlet exits 0 even when it reports findings, and without-Settingsit reads a settings file only from the-Pathfolder, 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-Settingswhen the host has a settings file. The command also exits 1 when the script, the settings file or the PSScriptAnalyzer module is missing, under bothpwsh -Commandandpwsh -File. Theperformance-discipline§1.1 verifier exits 1 on any record in the same way. update.ps1checks a release tag's signature the wayupdate.shdoes. 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 suggestingAPOTHEM_ALLOW_UNVERIFIED=1. Under Windows PowerShell 5.1, whichupdate.batruns, the check no longer stops the update on GnuPG's output, which it did even for a validly signed tag.install.ps1can verify a release tag under Windows PowerShell 5.1. Under Windows PowerShell 5.1, whichinstall.batruns, 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
mainto 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:mainis 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 doctorfails when a harness is not installed, where it now lists that harness and passes, and the translated installer-variables page lackedAPOTHEM_VERIFY,APOTHEM_RELEASE_BASEandNO_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. Soapothem install,updateanddifffor Claude Code and Qwen Code stopped with a traceback ending inno real CPython >= 3.10 interpreter found. The resolver now uses that interpreter as it reports itself. Its search ofPATHstill 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_PYTHONis tried first and the npm shim falls back topython3,pythonandpy -3when it fails, so it does not skip the probe.apothem diffrejectsall.apothem rollbackfails withrollback.no_recordfor a harness with no recorded install and carries on with the others.apothem update --harness glmwritesglm.tomlonly 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.ymlruns 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 thememory/,contexts/andlearning/stores, and never touchesplans/.apothem verifytakes--harness all, the installers write theapothemshim into a directory and never editPATH, 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 onlyapothem.vsixpasses to the build job, which adds it to thedist/assets that are hashed, signed and attested. Before,npxresolved 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_DIRoverrides the location.
1.1.0 - 2026-08-16
Fixed
statusandverifyno longer swallow a profile that fails to load.statushardcoded an empty warnings array and printed nothing in plain mode; with nothing installed there was nounknowndrift cell either, so the failure left no trace at all.verify --harness alldiscarded 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.ps1built its Windows install-root fallbacks with an unguardedJoin-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-workspacereports 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
Stophook no longer re-asserts the session-end protocol on every turn.Stopfires at the end of every assistant turn, not only at the end of a session, and the hook emittedhooks/messages/stop.mdverbatim 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 fromrules/context-management.mdandrules/auto-memory.mdare unchanged. Two environment variables tune it:APOTHEM_SESSION_END_MIN_STOPS(default3) sets the firing floor, andAPOTHEM_SESSION_END_ENABLED=0silences 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.yamlis 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/fortressclosed-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, andcompletion, 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 aspython -m apothemon 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 invscode-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/richprerequisites to the engine's declared constraints and document an inspect-first alternative to the pipe-to-shell one-liner.
Konvergensi konvensi lintas lingkungan
Bagaimana Apothem menjaga satu alur kerja operator tetap konsisten di tujuh belas lingkungan meskipun format konfigurasi dan permukaan enforcement dari tiap vendor berbeda-beda.
Komunitas
Komunitas Apothem — cara berkontribusi, tempat berdiskusi, peta jalan publik, dan kode etik.