Add first-class jcode harness support (identity + presence badges) - #825
Open
jmpnop wants to merge 1 commit into
Open
Add first-class jcode harness support (identity + presence badges)#825jmpnop wants to merge 1 commit into
jmpnop wants to merge 1 commit into
Conversation
Make jcode the 12th first-class harness: a SkillAgent identity and mark, AgentIntegrationFactory wiring, and an installer that writes jcode's native [hooks] entries plus an executable presence-hook wrapper, so a jcode pane gets the same busy / idle / error badge as every other harness. Additive only — no changes to jcode and none to sibling harnesses; the emitted OSC 3008 presence signal is byte-identical across harnesses.
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.
Closes #815
Summary
Adds jcode as a first-class coding-agent harness in Supacode, bringing the roster to twelve.
A jcode worktree now gets the same live presence badge (busy / idle / error) and harness identity —
mark, display name, and a Developer-settings row — as Claude, Codex, Kimi, and the rest, in place of
the previous identity-less generic shell.
The change is purely additive:
[hooks]mechanism —stock upstream jcode — which Supacode writes into the user's
~/.jcode/config.toml.other harness, so nothing downstream of the
SkillAgentenum — the presence reducer, badge views,sidebar fan-out, or notification flows — is touched.
What this adds
SkillAgent.jcode— a new harness identity: display namejcode, config directory~/.jcode,mark asset
jcode-mark. This slots jcode into the shared agent roster (the sorted settings list andidentity lookups).
AgentIntegrationFactorywiring — ajcode(...)builder (a hooks component plus the sharedskills component) mirroring the existing Kimi builder, so the integration installs, uninstalls, and
reports its state exactly like every other harness.
JcodeHookSettings+JcodeSettingsInstaller— install Supacode-owned entries in jcode'snative
[hooks]table (one per lifecycle event) plus an executable presence-hook wrapper at~/.jcode/hooks/supacode-presence.sh. Both artifacts are ownership-marked and safe around existinguser configuration (see below).
"Hooks in
~/.jcode/config.tomland skill in~/.jcode/skills/", so the integration isdiscoverable and toggleable alongside the others.
jcode-markicon asset — jcode's mark (a white "JC" on red), shipped as a full-color vectorasset rendered in its own colors (like the Claude Code and Codex marks).
How it works
Supacode's badges are driven by an OSC 3008 presence signal that a harness emits over its pane TTY
on lifecycle events; Supacode's terminal parses that signal and updates the pane's badge. Every harness
reuses one shared emitter, so the wire format is identical across all of them and is inert in any
terminal that does not handle OSC 3008.
Most harnesses inline that emitter as a shell one-liner in their hook config. jcode differs in one
respect: jcode execs a hook command directly — the command line is split shell-style but never run
through a shell — so a
printf/ps/caseone-liner cannot be inlined into the TOML the way itcan for a shell-invoking harness. To bridge that, the installer writes a small executable
presence-hook wrapper and points each entry in jcode's
[hooks]table at it:session_start/turn_start/turn_end/session_end) andexecs the wrapper.
#!/bin/sh) resolves the pane TTY and dispatches on$JCODE_HOOK_EVENT, mappingturn_start→ busy,turn_end→ idle (or error, keyed on jcode's own$JCODE_HOOK_STATUS), andsession start/end to their presence events.
uses, so the payload is byte-identical.
The wrapper is inert outside a Supacode surface (it exits early unless
SUPACODE_SURFACE_IDis set),so it never interferes with a jcode run started elsewhere. It carries a Supacode ownership marker and
is safe to delete — it is reinstalled on demand.
Safety around user configuration
The installer treats the user's config as sacrosanct:
[hooks]table. Re-installing is byte-identical. A user's own hookon one of the same lifecycle events is preserved — it is merged into an inline array alongside the
wrapper, never overwritten.
comments in
config.tomlare left untouched.value on a shared event. The wrapper file is deleted only when it carries Supacode's ownership marker,
so an unrelated user file at the same path is never removed.
comments; CRLF configs are handled; a non-UTF-8
config.tomlfails with a clear, actionable errorrather than corrupting the file.
Out of scope for this PR
TTY, which covers the common in-pane case. Binding a specific pane to a session that runs outside its
TTY (for example, surfacing "awaiting input" for a detached run) needs a
sessionfield on thepresence signal and a bridge that ingests jcode's NDJSON session stream; neither is wired yet, so
that binding is deliberately omitted rather than emitted with no consumer.
pre_tool/post_toolhooks. These are left to the user: apre_toolhook is a blocking gate,not a presence signal, so Supacode does not claim it.
inline array). The rare case of a hooked event whose value is a multi-line array is left untouched
rather than rewritten.
Type of change
ready)How was this tested?
Automated (all green):
JcodeSettingsInstallerTestscovers: a fresh install writes the[hooks]table and an executablewrapper; re-install is byte-idempotent; a user hook on the same lifecycle event is preserved (merged
into an array); uninstall removes only the managed entries and the wrapper while keeping user hooks,
and never deletes an unmarked user file sharing the wrapper's name; installed / outdated /
not-installed detection (including wrapper-body drift and partial installs); TOML value parsing
(string, inline array, literal, trailing comment); CRLF tolerance; invalid-UTF-8 handling; and the
wrapper's per-event dispatch.
SkillAgentTests, plus the agent-integration andsidebar coverage).
make check(swift-format + swiftlint) is clean,make build-appsucceeds, and the fullmake testsuite passes.
On-device (verified): installing the integration through the app wrote the managed
[hooks]entriesand the executable wrapper under
~/.jcode/, preserving existing user config, and running a real jcodeturn in a Supacode pane drove the pane's badge to busy on
turn_startand back to idle onturn_end.The error path (
turn_endwith an error status) and per-pane isolation are exercised by thewrapper-dispatch unit tests and the shared, per-surface OSC 3008 pipeline.
make checkpasses (format + lint)make testpassesobserved a real jcode turn drive the pane badge busy → idle on device (details above).
AI tool disclosure (optional)
for every line; no commit is authored or co-authored by an AI agent.
Checklist
Closes #above.ready.