Repository navigation
feat: cogos-harness plugin — portable CC membrane v1 - #16
Merged
Merged
Conversation
Adds cogos-harness, the first plugin in this marketplace of the hooks/MCP-server kind rather than skills-only: SessionStart/SessionEnd presence hooks, a compaction bypass path, ambient kernel-vitals + context-window proprioception, the cogos-kernel MCP server, and the btw/consolidate/handoff skills. Every hook degrades to a silent no-op wherever the kernel or a cog workspace is absent. Also fixes marketplace.json's name (cogos-skills -> plugins, matching the repo and the convention other marketplaces here already follow) and missing $schema, and adds the cogos-architecture plugin.json that package was missing.
F1: kernel-vitals-probe.py's disk watermark write fabricated a
~/workspaces/cog/.cog tree on any machine that had none, which then
made every sibling hook believe a cog workspace existed and
self-suppress. Gate the write on an already-existing workspace instead
of mkdir(parents=True) into a third party's home directory.
F2: plugin.json's description still advertised plan-usage
proprioception, which was dropped from the code; align it with
marketplace.json's already-correct wording.
F3: .mcp.json now resolves the kernel port via
${COGOS_KERNEL_PORT:-6931} — env-var substitution in MCP server URLs
does work in Claude Code — so drop the README's stale "Known
limitation" section that claimed otherwise.
F4: compaction-handoff.py unconditionally emitted a
<compaction_handoff> block promising a RECORD even when transcript,
in-flight tasks, and uncommitted work were all empty (e.g. a fresh
substrate-less HOME). Exit quietly instead of injecting an empty
promise to distrust the summary.
F5: unify the three independent kernel-endpoint knobs
(COGOS_KERNEL_URL, COGOS_KERNEL_PORT, and .mcp.json's hardcoded URL)
onto one precedence: COGOS_KERNEL_URL wins when set, COGOS_KERNEL_PORT
is the localhost-only default, applied consistently in both
kernel-vitals-probe.py and seat-identity-heal.py. README documents the
remaining .mcp.json gap (still port-only) honestly rather than as a
blocked-on-upstream limitation.
Contributor
Author
|
Dogfood verification at 7eeb2fa (clean isolated HOME, marketplace add from local clone, plugin install cogos-harness@plugins, hooks executed from the installed cache path with CLAUDE_PLUGIN_ROOT/CLAUDE_PLUGIN_DATA set as the harness would):
Note: kernel-present path was exercised (this machine's kernel is live on :6931, which is machine-scoped, not HOME-scoped); the kernel-absent degradation paths were separately verified in the review pass. |
This was referenced Aug 3, 2026
chazmaniandinkle
added a commit
that referenced
this pull request
Aug 3, 2026
…loses #17 (#18) * fix: kernel-gated session lifecycle (auto-register, heartbeat, end) Presence was workspace-gated: a seat with no cog workspace never auto-registered on the kernel session registry, even though the kernel was reachable and willing (#17, same predicate-confusion family as F1 in #16, inverted direction). Makes all three lifecycle touchpoints kernel-gated instead: - user-scope-session-start.py: after the existing workspace-handler delegation (kept intact and tried first), a direct-registration fallback fires only when no workspace handler ran AND a short kernel probe succeeds. POSTs /v1/sessions/register with session_id (from hook stdin), workspace=cwd, role=$COGOS_SEAT_ROLE or "claude-code", hostname, extras.source=plugin-startup. - user-scope-proprioception.py: when the already-cached kernel-vitals read shows the kernel reachable, also POSTs the session heartbeat (/v1/sessions/{id}/heartbeat) -- no new probe, at most once per turn, silent no-op when the kernel is absent. - user-scope-session-end.py: mirrors session-start -- direct /v1/sessions/{id}/end fallback, same probe gate, only when the workspace handler didn't run. All three resolve the kernel via the same COGOS_KERNEL_URL / COGOS_KERNEL_PORT precedence as seat-identity-heal.py and kernel-vitals-probe.py. Every new network call is short-timeout and fails open silently, matching the existing hook contract. Verified against the live kernel: register -> heartbeat (last_seen advances) -> end, in a clean isolated HOME with no cog workspace, plus delegation-path-untouched and dead-kernel-port cases (all hooks exit 0 silently, no hang). Bumps cogos-harness 0.1.0 -> 0.2.0 in plugin.json and marketplace.json. * fix: gate the presence fallback on the registry, not handler existence Adversarial review of the #17 fix found that handler-existence was standing in for registration, which is the same predicate confusion #17 is about. The canonical 51-presence-started.py / 51-presence-ended.py handlers emit presence.started / presence.ended events on the kernel BUS; neither touches the session registry. Three consequences, all reproduced against a live kernel: 1. On any machine WITH a cog workspace -- the environment #17 was reported from -- delegation ran, handler_invoked suppressed the fallback, and the seat still never reached the registry. #17 unfixed in its own reproduction environment. 2. A workspace shipping 51-presence-ended.py but not 51-presence-started.py registered via the start fallback and then had the end fallback suppressed by the bus-only end handler: a seat left active=true, ended=false, forever. 3. /v1/sessions/register is a full-row replace, not a field merge (the fact seat-identity-heal.py exists to repair). The unconditional fallback fired on resume/compact SessionStart too, overwriting a durable seat role with role=claude-code, extras.source=plugin-startup. All three collapse into one predicate. Both hooks now ask the registry itself -- GET /v1/sessions/presence, which lists live not-yet-ended sessions -- and act only on what it reports: register when the session is genuinely absent, end when it is genuinely still live. That call replaces the GET /health probe rather than adding to it, so the gate is one round trip, not two. Delegation stays preferred and still runs first; it just no longer decides. Also cuts the proprioception heartbeat timeout 1.0s -> 0.25s. That call is the only network work on the UserPromptSubmit critical path, and its reachability gate is a cache that can report a hung kernel as reachable for up to the 90s vitals TTL. Measured against a listener that accepts and never answers: 1.14s per turn before, 0.39s after. README updated where it described the old gate. * fix: align registration vocabulary with fleet conventions extras.source passes through the harness SessionStart source value (startup|resume|clear|compact) instead of inventing plugin-startup; provenance moves to extras.via. End reason uses the established session_end_hook instead of plugin-shutdown. Verified live: register row carries {source: startup, via: cogos-harness}; end row carries end_reason: session_end_hook.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
First increment of graduating the hand-wired CogOS Claude Code membrane into a versioned marketplace artifact, per the harness-membrane audit's "first increment" recommendation.
cogos-harnessplugin — the first plugin in this marketplace of the hooks/MCP-server kind, not just skills. Ships:cogos-kernel, HTTP connection to a locally-running CogOS kernel (http://127.0.0.1:6931/mcp).user-scope-session-start.py+user-scope-session-end.py(presence dispatch),seat-identity-heal.py(SessionStart role self-heal),compaction-handoff.py(post-compaction bypass path),user-scope-proprioception.py(ambient branch/clock/model/context-window header onUserPromptSubmit),kernel-vitals-probe.py(detached kernel-health/log/release/PR collector the proprioception hook reads from, never called synchronously).btw,consolidate,handoff.marketplace.jsonnamecorrected fromcogos-skillstoplugins(matches the repo, and the conventionoscine's own marketplace already follows: marketplace name = repo basename); added the missing$schemakey; addedcogos-architecture's missing.claude-plugin/plugin.json(it was declared inmarketplace.jsonwith no manifest — installing it specifically would have misbehaved).What's excluded, and why
dispatch-model-probe.py— the audit named it a "by-reference companion" of the proprioception hook, but its only call site there has been commented out (dead code, kept only for easy revival). It also reads the local Claude Code OAuth credentials file directly and pingsapi.anthropic.comwith them — appropriate for one operator's own incident-response tooling, not for default behavior anyone who installs this plugin gets. Excluded outright, not ported.use S24%·W18%-style segment) — depended on a statusline side-channel cache that isn't part of this plugin and isn't itself portable membrane. Dropped rather than partially ported. The self-contained context-window (ctx N%) segment is kept.kernel-vitals-probe.pyalso read a specific private repo's comment ledger to surface an unrelated personal writing project's review queue (repo constant, thread-state diffing, abook ✎Nline segment). That entire code path is removed from the shipped version, not disabled — the audit didn't flag this coupling explicitly, it surfaced during the port.pull-context-dispatch— one of the four skills named in the audit's proposed increment, but it's already published in this marketplace undercogos-workflow(landed same-day, ahead of this branch). Not duplicated here to avoid two copies drifting;cogos-harness+cogos-workflowcompose for the full skill set.What stays user-scope (not absorbed into this plugin)
CLAUDE.mdoperating principles, the memory corpus,settings.jsonrisk-posture flags (defaultMode, permission allow-lists, the variousskip*PermissionPromptflags), the default-agent/model-tiering setting, and node bootstrap (installing/starting thecogosbinary itself) — all documented in the plugin's own README under "What stays outside this plugin". This plugin configures a client against an already-running kernel; it does not install or start one.Known limitation
The bundled MCP server's port isn't env-parameterized — Claude Code plugin
.mcp.jsondoesn't support arbitrary${ENV_VAR}substitution in server URLs (only theCLAUDE_PLUGIN_*/CLAUDE_PROJECT_DIRplaceholders resolve there), so a non-default kernel port means hand-editing the installed plugin's.mcp.json. Documented in the plugin README rather than worked around in this PR.Scrub check (public-artifact, mandatory)
Ran against every new/changed file (
git diff --cached --name-only):/Users/...paths: none found.slowbro,chaz,darkstar,eclipse,chazmaniandinkle): none found. (Pre-existingmyrgic@users.noreply.github.comorg owner address inmarketplace.jsonis untouched and isn't personal.)credentials/OAuthmention is prose in the README explaining whydispatch-model-probe.pywas excluded, not a value.handoffskill (slowbro-laptop-*) were genericized to<hostname>-*during the port./Users/slowbro/...example paths in a since-superseded draft of thepull-context-dispatchskill were the reason that skill isn't duplicated here at all (see above) — moot once excluded.Dogfood plan (follow-up, not this PR)
Tap
myrgic/pluginsand installcogos-harness@pluginsin a real seat; confirm the installed copy serves hooks in place of the hand-wired~/.claude/hooks/files it was cut from. Tracked as follow-up work, intentionally out of scope here per the audit's own "first increment" framing (prove the shape first).Test plan
python3 -m py_compileon all six hooks — clean.claude plugin validate ./plugins/cogos-harness --strict— passes.claude plugin validate ./plugins/cogos-architecture --strict— passes (new manifest).claude plugin validate . --strict(marketplace root) — passes.