I reviewed the current main branch and found 5 issues worth triage. I checked these against open and closed GitHub issues before filing.
1. Explorer TUI truncates rows by string length instead of terminal display width
Area: @poe-code/design-system
Severity: medium
Confidence: high
Score: 78
What I found:
The shared explorer renderer is display-width unaware in its own truncation and centering logic. ScreenBuffer can render graphemes and wide cells correctly, but list/header/detail code slices strings before they reach ScreenBuffer, so wide task names, plan names, badges, filters, or empty-state text can be mismeasured.
This affects the Maestro task explorer and the plan browser because both build rows from user-controlled task or file names.
Evidence:
- /home/gjones/poe-code/packages/design-system/src/explorer/render/list.ts:100 computes available cells with string length, not display width.
- /home/gjones/poe-code/packages/design-system/src/explorer/render/list.ts:101 slices row titles by UTF-16 code units, then lines 108-110 write one code unit per column.
- /home/gjones/poe-code/packages/design-system/src/explorer/render/list.ts:136-144 center and truncate list text with text.length and slice.
- /home/gjones/poe-code/packages/design-system/src/explorer/render/header.ts:52-56 and 68-75 use length/slice for borders and filter text; /home/gjones/poe-code/packages/design-system/src/explorer/render/detail.ts:128-135 does the same for detail lines.
- /home/gjones/poe-code/packages/design-system/src/dashboard/buffer.ts:34-42 already understands graphemes and wide cells, so the bug is in pre-truncating text before ScreenBuffer can place it safely.
- Nearby explorer renderer tests snapshot ASCII fixtures only; design-system table/help tests cover wide glyph handling elsewhere.
2. MCP request timeouts do not cancel the server-side tool call
Area: tiny-mcp-client
Severity: medium
Confidence: high
Score: 78
What I found:
The MCP client has two timeout/cancellation paths with different semantics. An explicit AbortSignal passed to callTool sends notifications/cancelled to the MCP server, but the configured JSON-RPC request timeout only rejects the local promise and removes the pending request.
That means a Poe Agent MCP server configured with timeout can appear to fail fast in the agent while the server keeps executing the original tool. This is most risky for expensive tools, tools that hold locks, and tools with side effects where the caller retries after the timeout.
Evidence:
packages/poe-agent/src/runtime/plugin-api-impl.ts:63-66 - The Poe Agent MCP plugin maps a server config timeout to tiny-mcp-client requestTimeoutMs, so this timeout path is user-facing.
packages/tiny-mcp-client/src/internal.ts:451-482 - callTool captures the JSON-RPC request id and sends notifications/cancelled only when an explicit AbortSignal aborts.
packages/tiny-mcp-client/src/internal.ts:3221-3246 - JsonRpcMessageLayer.sendRequest starts the request timeout, then only deletes pendingRequests and rejects when it fires; it does not notify the peer that the request was cancelled.
packages/tiny-mcp-client/src/transports.test.ts:1410-1439 - Existing timeout coverage asserts local rejection and pending-request cleanup, but not server-side cancellation.
packages/tiny-mcp-client/src/mcp-client-sdk.test.ts:260-294 - The explicit abort tests show the intended cancellation behavior by asserting that a server sees the cancellation notification.
packages/tiny-mcp-client/README.md:1-37 - The package README identifies tiny-mcp-client as the shared MCP client package; no config option documents that request timeouts are local-only.
Suggested next step:
Make request-timeout expiry cancel the remote request when the request id is known. The least invasive shape is to let sendRequest expose timeout expiry to callTool, or move timeout handling for MCP tool calls into callTool so it can share the same notifications/cancelled path used by explicit aborts.
3. MCP serve help renders the tool catalog with direct chalk styling
Area: poe-code
Severity: low
Confidence: high
Score: 64
What I found:
The MCP tool catalog shown after mcp serve --help is a separate renderer that imports chalk and constructs a custom layout. That bypasses the package's design-system primitives even though it is appended to a design-system-formatted help screen.
This creates a consistency gap now and makes later design-language changes miss one of the more important setup/help surfaces.
Evidence:
- /home/gjones/poe-code/src/cli/mcp-server.ts:9 imports chalk directly in CLI production code.
- /home/gjones/poe-code/src/cli/mcp-server.ts:90-109 formats the user-visible tool catalog with chalk.magenta, chalk.cyan, chalk.dim, and chalk.yellow instead of @poe-code/design-system text/help/table primitives.
- /home/gjones/poe-code/src/cli/commands/mcp.ts:85 appends that catalog to
mcp serve --help via addHelpText("after", ...), outside the custom help formatter in src/cli/program.ts.
- /home/gjones/poe-code/packages/design-system/src/components/symbols.ts and packages/design-system/src/prompts/primitives/log.ts show existing theme/output-format-aware primitives that this path bypasses.
- Nearby help tests cover root/spawn/runtime help formatting but do not snapshot the MCP serve tool catalog.
4. launch start waits for readiness without spinner or progress output
Area: process-launcher
Severity: low
Confidence: medium-high
Score: 57
What I found:
poe-code launch start can wait for readiness before returning, but the interactive command path emits no spinner or progress message while that wait is in progress. The daemon child is spawned with inherited stdio, but the supervised process output is written through the launcher log path, so the user is not guaranteed to see startup progress at the command line.
This is not a correctness bug in the process launcher. It is a CLI feedback bug for a command whose normal path can wait up to 30 seconds, especially when the user passed a readiness option.
Evidence:
src/cli/commands/launch.ts:39-54 - launch start exposes readiness options that tell the command to wait for a log pattern or TCP port before reporting running.
src/cli/commands/launch.ts:64-83 - The action creates execution resources and then awaits startLaunch directly; there is no withSpinner, spinner, or progress logging around the long-running start operation.
packages/process-launcher/src/launcher.ts:82-117 - startManagedProcess waits for a ready record and defaults startupTimeoutMs to 30,000ms when no override is passed.
packages/process-launcher/src/launcher.ts:405-422 - waitForRecord polls until readiness succeeds or the startup deadline expires, so the awaited CLI operation can legitimately last the full timeout.
packages/process-launcher/src/supervisor/supervisor.ts:130-156 - The supervisor transitions to restarting and waits on the ready check before marking the process running.
src/cli/commands/launch-command.test.ts:72-132 - CLI tests validate forwarding readiness options to the SDK, but do not assert any spinner or progress behavior for the wait.
packages/process-launcher/src/process-launcher.test.ts:245-269 - Process-launcher tests cover timeout cleanup for startup waits, confirming the wait path is expected behavior.
packages/process-launcher/README.md:1-3 - The package README describes launch as managing long-running dev tools from the CLI.
Suggested next step:
Wrap startLaunch and restartLaunch readiness waits in the design-system spinner used by other long-running CLI commands. Include the managed process id and readiness mode in the message, and stop the spinner before printing any terminal error.
5. Wrapped Poe command timeouts can leave the real child process running
Area: @poe-code/agent-harness-tools
Severity: high
Confidence: 4
Score: 34
What I found:
Synchronous Poe command runs use wrapForLogTee by default, which turns the requested command into a sh -c wrapper with a subshell piped through tee. When activityTimeoutMs or an abort fires, createAbortSync only calls handle.kill("SIGTERM") on the wrapper handle. That can terminate the wrapper without terminating the real command running inside the subshell.
Why it matters:
A timed-out or aborted wrapped command can keep doing work after Poe Code reports ActivityTimeoutError and marks the job lost. In host runtime paths this can leak long-running child processes; in remote runtime paths it can leave work running until the environment is eventually closed, which is especially bad for commands that mutate files, consume paid resources, or continue using credentials.
Evidence:
packages/agent-harness-tools/src/run-poe-command.ts:406 creates the abort helper around a single RunHandle.
packages/agent-harness-tools/src/run-poe-command.ts:537 sends SIGTERM only through handle.kill("SIGTERM").
packages/agent-harness-tools/src/log-stream.ts:32 and packages/agent-harness-tools/src/log-stream.ts:35 build the wrapped command as ({ (${command}); ... } 2>&1 | tee ...).
packages/agent-harness-tools/src/run-poe-command.test.ts:933 verifies timeout behavior with a mock kill() flag, but it does not model the shell process tree.
- Local reproduction using the same shell shape printed:
{"wrapperPid":2601110,"innerPid":"2601113","innerAliveAfterWrapperSigterm":true}
Suggested next step:
Run wrapped commands in a killable process group or make the execution environment expose process-tree termination for wrapped runs. The regression test should use a realistic shell/tee wrapper or a fake environment that models a child process surviving wrapper SIGTERM, not just a boolean kill() spy.
Validation:
- Add a focused unit or integration test in
packages/agent-harness-tools that starts a wrapped command with an inner process that ignores SIGTERM, triggers activityTimeoutMs, and asserts the inner process is terminated or the process group is killed.
- Run the focused package test with
npm run test:unit -- --run packages/agent-harness-tools/src/run-poe-command.test.ts.
- Verify the job state still transitions to
lost on timeout and no child process remains after the command rejects.
Duplicate checks
- Refreshed issue cache for
poe-platform/poe-code before preparing this issue.
- Prepared at
2026-06-08T05:49:30.324Z.
- Checked candidate metadata for duplicate links and exact GitHub title matches.
- Source candidates are stored under
/home/gjones/poe-code-issues/candidates.
I reviewed the current
mainbranch and found 5 issues worth triage. I checked these against open and closed GitHub issues before filing.1. Explorer TUI truncates rows by string length instead of terminal display width
Area:
@poe-code/design-systemSeverity: medium
Confidence: high
Score: 78
What I found:
The shared explorer renderer is display-width unaware in its own truncation and centering logic.
ScreenBuffercan render graphemes and wide cells correctly, but list/header/detail code slices strings before they reachScreenBuffer, so wide task names, plan names, badges, filters, or empty-state text can be mismeasured.This affects the Maestro task explorer and the plan browser because both build rows from user-controlled task or file names.
Evidence:
2. MCP request timeouts do not cancel the server-side tool call
Area:
tiny-mcp-clientSeverity: medium
Confidence: high
Score: 78
What I found:
The MCP client has two timeout/cancellation paths with different semantics. An explicit
AbortSignalpassed tocallToolsendsnotifications/cancelledto the MCP server, but the configured JSON-RPC request timeout only rejects the local promise and removes the pending request.That means a Poe Agent MCP server configured with
timeoutcan appear to fail fast in the agent while the server keeps executing the original tool. This is most risky for expensive tools, tools that hold locks, and tools with side effects where the caller retries after the timeout.Evidence:
packages/poe-agent/src/runtime/plugin-api-impl.ts:63-66- The Poe Agent MCP plugin maps a server config timeout to tiny-mcp-client requestTimeoutMs, so this timeout path is user-facing.packages/tiny-mcp-client/src/internal.ts:451-482- callTool captures the JSON-RPC request id and sends notifications/cancelled only when an explicit AbortSignal aborts.packages/tiny-mcp-client/src/internal.ts:3221-3246- JsonRpcMessageLayer.sendRequest starts the request timeout, then only deletes pendingRequests and rejects when it fires; it does not notify the peer that the request was cancelled.packages/tiny-mcp-client/src/transports.test.ts:1410-1439- Existing timeout coverage asserts local rejection and pending-request cleanup, but not server-side cancellation.packages/tiny-mcp-client/src/mcp-client-sdk.test.ts:260-294- The explicit abort tests show the intended cancellation behavior by asserting that a server sees the cancellation notification.packages/tiny-mcp-client/README.md:1-37- The package README identifies tiny-mcp-client as the shared MCP client package; no config option documents that request timeouts are local-only.Suggested next step:
Make request-timeout expiry cancel the remote request when the request id is known. The least invasive shape is to let
sendRequestexpose timeout expiry tocallTool, or move timeout handling for MCP tool calls intocallToolso it can share the samenotifications/cancelledpath used by explicit aborts.3. MCP serve help renders the tool catalog with direct chalk styling
Area:
poe-codeSeverity: low
Confidence: high
Score: 64
What I found:
The MCP tool catalog shown after
mcp serve --helpis a separate renderer that importschalkand constructs a custom layout. That bypasses the package's design-system primitives even though it is appended to a design-system-formatted help screen.This creates a consistency gap now and makes later design-language changes miss one of the more important setup/help surfaces.
Evidence:
mcp serve --helpvia addHelpText("after", ...), outside the custom help formatter in src/cli/program.ts.4. launch start waits for readiness without spinner or progress output
Area:
process-launcherSeverity: low
Confidence: medium-high
Score: 57
What I found:
poe-code launch startcan wait for readiness before returning, but the interactive command path emits no spinner or progress message while that wait is in progress. The daemon child is spawned with inherited stdio, but the supervised process output is written through the launcher log path, so the user is not guaranteed to see startup progress at the command line.This is not a correctness bug in the process launcher. It is a CLI feedback bug for a command whose normal path can wait up to 30 seconds, especially when the user passed a readiness option.
Evidence:
src/cli/commands/launch.ts:39-54- launch start exposes readiness options that tell the command to wait for a log pattern or TCP port before reporting running.src/cli/commands/launch.ts:64-83- The action creates execution resources and then awaits startLaunch directly; there is no withSpinner, spinner, or progress logging around the long-running start operation.packages/process-launcher/src/launcher.ts:82-117- startManagedProcess waits for a ready record and defaults startupTimeoutMs to 30,000ms when no override is passed.packages/process-launcher/src/launcher.ts:405-422- waitForRecord polls until readiness succeeds or the startup deadline expires, so the awaited CLI operation can legitimately last the full timeout.packages/process-launcher/src/supervisor/supervisor.ts:130-156- The supervisor transitions to restarting and waits on the ready check before marking the process running.src/cli/commands/launch-command.test.ts:72-132- CLI tests validate forwarding readiness options to the SDK, but do not assert any spinner or progress behavior for the wait.packages/process-launcher/src/process-launcher.test.ts:245-269- Process-launcher tests cover timeout cleanup for startup waits, confirming the wait path is expected behavior.packages/process-launcher/README.md:1-3- The package README describes launch as managing long-running dev tools from the CLI.Suggested next step:
Wrap
startLaunchandrestartLaunchreadiness waits in the design-system spinner used by other long-running CLI commands. Include the managed process id and readiness mode in the message, and stop the spinner before printing any terminal error.5. Wrapped Poe command timeouts can leave the real child process running
Area:
@poe-code/agent-harness-toolsSeverity: high
Confidence: 4
Score: 34
What I found:
Synchronous Poe command runs use
wrapForLogTeeby default, which turns the requested command into ash -cwrapper with a subshell piped throughtee. WhenactivityTimeoutMsor an abort fires,createAbortSynconly callshandle.kill("SIGTERM")on the wrapper handle. That can terminate the wrapper without terminating the real command running inside the subshell.Why it matters:
A timed-out or aborted wrapped command can keep doing work after Poe Code reports
ActivityTimeoutErrorand marks the job lost. In host runtime paths this can leak long-running child processes; in remote runtime paths it can leave work running until the environment is eventually closed, which is especially bad for commands that mutate files, consume paid resources, or continue using credentials.Evidence:
packages/agent-harness-tools/src/run-poe-command.ts:406creates the abort helper around a singleRunHandle.packages/agent-harness-tools/src/run-poe-command.ts:537sendsSIGTERMonly throughhandle.kill("SIGTERM").packages/agent-harness-tools/src/log-stream.ts:32andpackages/agent-harness-tools/src/log-stream.ts:35build the wrapped command as({ (${command}); ... } 2>&1 | tee ...).packages/agent-harness-tools/src/run-poe-command.test.ts:933verifies timeout behavior with a mockkill()flag, but it does not model the shell process tree.Suggested next step:
Run wrapped commands in a killable process group or make the execution environment expose process-tree termination for wrapped runs. The regression test should use a realistic shell/tee wrapper or a fake environment that models a child process surviving wrapper
SIGTERM, not just a booleankill()spy.Validation:
packages/agent-harness-toolsthat starts a wrapped command with an inner process that ignoresSIGTERM, triggersactivityTimeoutMs, and asserts the inner process is terminated or the process group is killed.npm run test:unit -- --run packages/agent-harness-tools/src/run-poe-command.test.ts.loston timeout and no child process remains after the command rejects.Duplicate checks
poe-platform/poe-codebefore preparing this issue.2026-06-08T05:49:30.324Z./home/gjones/poe-code-issues/candidates.