@code-yeongyu/senpi-codemode
v2026.8.22-2
Published
Source-only senpi extension package for codemode evaluation tools
Downloads
23,853
Maintainers
Readme
@code-yeongyu/senpi-codemode
@code-yeongyu/senpi-codemode is Senpi's source-only Code Mode extension. It
registers the persistent-kernel eval execution surface for every eligible
model. eval owns one persistent kernel per enabled language and re-registers
at session start after configuration, interpreter availability, and active
task-tool names are known.
Capabilities
- Persistent JavaScript, Python, Ruby, and Julia cells. State survives later cells in the same language until reset, restart, or session disposal.
- Timeout detachment for interactive
eval: long pure-compute cells return a handle and continue in their existing kernel. Completion is injected with the final value/error and buffered output; useeval({ action: "peek"|"stop", cell_id })to inspect or terminate a detached cell. A running peek preserves the original code and summary together with current output, phase, status events, tool-call summaries, elapsed duration, and structured display state; a terminal peek preserves the exact final result. - Loopback, bearer-authenticated kernel bridge with bounded JSONL frames.
- Structured status events for file operations, environment access, phases, bridge activity, and delegated task progress.
- One versioned
senpi.eval.executionevent at terminal cell settlement. The in-process event bus receives bounded per-call arguments and result previews for extension-owned consumers; external RPC clients receive a 32 KiB-capped metadata-only projection with wall time, kernel time, exact call counts, pending-call counts, and bounded per-tool aggregates. - Bounded streaming output with head/tail previews, column clamping, and session-adjacent spill files for large streams.
- TUI and HTML-export rendering for syntax-highlighted cells, status rows, task progress, structured display values, truncation warnings, and image fallbacks.
- Runtime identity badges in eval headers —
eval py (3.14.7, ~/.venv/bin/python3),eval js (node 26.7.0, /opt/…/bin/node)— with the sameruntimeinfo onEvalToolDetailsand itscellsfor RPC consumers; interpreter detection resolves absolute executable paths, and the eval prompt host line names the JS runtime (node/bun). - JavaScript import rewriting for supported local modules and package imports in the persistent Node.js worker.
- GPT models receive a terse
evalprompt dialect that prioritizes composing active tools throughtool.<name>(args)and documents detach-on-timeout.
Kernels
| Language | Default | Runtime | Notes |
| --- | --- | --- | --- |
| js | enabled | Node.js worker | Requires Node.js 24 or newer; supports top-level await and return. |
| py | enabled | python3 or python | Optional interpreter detected at session start. |
| rb | disabled | ruby | Optional interpreter detected at session start. |
| jl | disabled | julia | Optional interpreter detected at session start. |
A missing optional interpreter removes that language from the session's eval
schema; it is not an installation failure.
Settings
Configuration is loaded in this order:
.senpi/codemode.jsonin the session working directory~/.senpi/agent/codemode.json- Built-in defaults
{
"languages": {
"py": true,
"js": true,
"rb": false,
"jl": false
},
"cellTimeoutSeconds": 30,
"parallelPoolWidth": 4,
"taskTools": {
"task": "task",
"output": "task_output"
},
"outputSink": {
"headBytes": 20480,
"maxColumns": 768
},
"statusEvents": true
}| Key | Default | Effect |
| --- | --- | --- |
| languages | py/js enabled; rb/jl disabled | Selects desired languages before interpreter detection. |
| cellTimeoutSeconds | 30 | Idle timeout for one cell unless the call supplies timeout; interactive calls detach by default and print/json calls error. |
| parallelPoolWidth | 4 | Maximum concurrent parallel() thunks. |
| taskTools.task | "task" | Registered tool name used by agent(). |
| taskTools.output | "task_output" | Registered tool name used by output(). |
| outputSink.headBytes | 20480 | Bytes retained from the beginning of a middle-truncated preview; 0 disables it. |
| outputSink.maxColumns | 768 | Maximum rendered output columns; 0 disables column clamping. |
| statusEvents | true | Enables kernel status-event forwarding and rendering. Each cell retains at most 100 status rows; after overflow, one omitted-count row precedes the latest 99 events. |
SENPI_CODEMODE_PY, SENPI_CODEMODE_JS, SENPI_CODEMODE_RB, and
SENPI_CODEMODE_JL override the corresponding file setting. 1 or true
enables; 0 or false disables. Any other value leaves the file setting in
effect.
Malformed JSON or invalid settings fall back to defaults with a warning.
Cell helpers
Python, JavaScript, Ruby, and Julia expose the same conceptual helpers. Python,
Ruby, and Julia use trailing keyword options; JavaScript uses one trailing
options object and asynchronous helpers are await-able.
| Helper | Contract |
| --- | --- |
| display(value) | Emits text, structured JSON, markdown, or supported image display data. |
| print(value, ...) | Emits text output. |
| read(path, offset?, limit?) | Reads text with 1-indexed line slicing. local:// paths resolve under the session artifact root. |
| write(path, content) | Creates parent directories and writes text. local:// paths persist in the session artifact root. |
| env(key?, value?) | Reads all kernel environment values, one value, or sets one value. |
| tool.<name>(args) | Invokes an active Senpi tool through the normal pi.executeTool pipeline. |
| tool_schema(name?) | Returns a tool's parameter schema without calling it; omit name to list tool names. |
| completion(prompt, model?, system?, schema?) | Requests a one-shot host completion; schema asks the host to parse structured output. |
| agent(prompt, ...) | Delegates to the configured active taskTools.task tool. Supports background handles and structured JSON results. |
| output(ids, format?, offset?, limit?) | Delegates transcript retrieval to the configured active taskTools.output tool. |
| parallel(thunks) | Runs thunks through the configured bounded pool while preserving input order. |
| pipeline(items, ...stages) | Applies stages left to right with a barrier between stages. |
| log(message) / phase(title) | Emits progress text and starts a status phase. |
When a tool.<name>() call fails argument validation, the error delivered back
into the cell carries the tool's expected parameters, so the cell can correct the
arguments and retry instead of falling back to one-at-a-time tool calls.
tool_schema() exposes the same catalog up front.
agent() is available only when the configured task tool is active in the
session. output() similarly requires the configured task-output tool and
returns immediately: a running task reports its current status, while completed
tasks return the requested transcript. Missing tools produce a clear
availability error instead of importing an orchestration package. agent()
delegates through the tool contract, so task-engine permissions, progress
updates, and transcripts remain owned by that engine.
isolated, apply, and merge are accepted for compatibility but emit a
warning because this task-engine integration has no isolation model.
Required summary
Every eval run call MUST include a summary — one line in the user's
conversational language stating what the cell does and for what purpose (e.g.
a Korean conversation produces a Korean summary such as "src 전체에서
legacyClient 사용처 집계"). The summary is shown in the TUI while the cell
runs and in the finished result, so you can always tell what is running and
why. Values longer than 80 characters are force-truncated. A run request
without a summary fails with a teaching error.
Detached cells
eval accepts on_timeout: "detach"|"error". The default is "detach" in
interactive TUI, RPC, and app-server sessions; print and JSON one-shot runs
default to "error" so their result is never silently detached. A detached
cell keeps only its own language kernel busy. A new same-language call returns
a busy error with its cell id and output tail; calls in other languages continue
normally. Do not re-run the cell.
While any cell is detached, the interactive footer shows a highlighted
↗ <language> · <summary> status on the extension status line (the cell id
when the call had no summary), clearing as soon as the last detached cell settles.
Use eval({ action: "peek", cell_id }) for its state and buffered output, or
eval({ action: "stop", cell_id }) to cancel it. Python stop interrupts the
existing kernel and preserves variables. JavaScript stop kills and restarts its
worker, so JavaScript VM state is lost. Detached completion messages state when
kernel variables are available to the next eval cell; oversized buffered output
is written under the session local root and referenced as local://….
Output and artifacts
Cell output is streamed while the cell runs. Large streams spill to an absolute
file after the default 50 KiB threshold. With a session file such as
/path/session.jsonl, artifacts live in /path/session-artifacts/; sessions
without a file use a unique temporary directory. Truncated results include a
plain-path notice such as [Full output: /absolute/path/eval-….log].
Deliberate differences from oh-my-pi
- There is no
budgethelper. - There is no
artifact://protocol. Spill references are ordinary absolute file paths. agent()andoutput()compose registered task tools throughpi.executeTool; this package does not import a task-engine workspace package.- Task transcript formats are limited to full (
raw) and trailing (tail) output. Query, JSON, and stripped metadata formats are task-engine concerns.
Security and lifecycle
Kernels run locally with the invoking user's permissions. The bridge listens on loopback only and authenticates each session with a random bearer token. Session generations fence retired kernels and callbacks; each cell settles once across completion, errors, cancellation, timeout, bridge failure, or a kernel crash.
GPT models use the same JavaScript eval worker trust boundary as other JavaScript cells;
there is no separate execution runtime. eval is excluded from the nested tool
namespace to prevent recursive execution.
Validation
cd packages/senpi-codemode
npm test
cd ../..
npm run checkDirect real-surface QA drivers live in scripts/qa-*.ts: kernel cells
(qa-py-cell.ts, qa-js-cell.ts, qa-rb-cell.ts, qa-jl-cell.ts), end-to-end
extension execution (qa-e2e-eval.ts), and renderer output
(qa-render-dump.ts).
Nested tool-call widgets
When an eval cell invokes tool.<name>(...), the result panel can render a
nested widget for the invoked tool. The widget captures bounded args, duration,
and a sanitized 160 code points result preview; the rendering path is
always-on and does not depend on any toggle or session flag.
The capture budget is fixed at 30 enriched calls per cell, with a 4096-character serialized args budget. Previews are capped at 160 code points, and collapsed widgets stay within the 8 lines collapsed widget budget.
Entries without args — including old sessions, reserved/completion rows, and calls past the cap — render as plain rows. Edit renders a fallback row by design, even when its args are present.
