fix(chat): pending shell row stops impersonating an error; chips survive a shell-driven session - #99

Merged
jack-champagne merged 2 commits into
local/amicodefrom
rchari/chat-row-and-rail-gate
Jul 29, 2026
Merged

fix(chat): pending shell row stops impersonating an error; chips survive a shell-driven session#99
jack-champagne merged 2 commits into
local/amicodefrom
rchari/chat-row-and-rail-gate

Conversation

@Rchari1

Copy link
Copy Markdown
Member

Two reports from the same screenshot, two unrelated causes. Both were untestable where they lived, and both shipped a user-visible bug, so each rule is extracted to a pure module with tests.

1. "A constant error not going away even though my session is progressing"

The shell row's label chain was command ?? title ?? description. A pending bash part has no input.command yet, so it fell through to the model's free-text description and rendered a full prose sentence in the slot where users read a command — and held it for the command's whole duration (1m55s observed).

The text was a paraphrase of agent guidance:

"A local launch is REFUSED by amico-run while this solver is selected (exit 64), so attempting one only wastes a turn."

Nothing had failed. The solve underneath was on iteration 29 with frames on disk, and the solver was piccolo, so the sentence wasn't even applicable. It just looked exactly like a hard error that wouldn't clear.

The description fallback is worth keeping — it's often a useful "Install deps" — so the fix isn't to drop it but to stop it impersonating a command: unwrap quotes, first line only, clamp to 72 chars with an ellipsis.

2. "What happened to the chips at the top"

The rail's session gate was part.tool.startsWith("amicode_"). A session that did its amicode work through the shell therefore showed no chips at all.

That's what happened here: the same session created a problem workspace, wrote a solvespec.json, and drove a solve to iteration 29 — entirely via bash + amico-run, never calling an amicode_* tool. The rail stayed hidden the whole time despite having real entities to describe.

The gate now also matches a shell part whose command drives amicode (amico-run, .amico/problems, amico plan|spec). It stays session-scoped, which is the entire point of the gate — an unrelated session still shows nothing, and there's a test pinning that.

The refetch key is deliberately not broadened. Shell parts don't mutate the problem view through the tool seam, so counting them would refetch the problem on unrelated shell activity. any (the gate) widens; completed (the refetch key) doesn't.

Testing

15 new tests, including the exact reported strings as regression cases: the quoted guidance sentence must clamp and lose its quote, and a shell-launched solve must open the gate while git status must not. Plus the fiddly edges — pending parts with no input, empty-string commands not beating a usable description, exact clamp boundaries.

ui: 318 pass. tsgo clean in ui and app. Both fixes verified present in the built darwin-arm64 binary (the clamp constant and the shell markers; symbol names are minified away).

Note

These are UI-only. Neither is deploy-gated — worth saying because the chips in particular looked like they might be fixed by shipping something, and they weren't: the gate was rejecting a legitimate session shape.

Rchari1and others added 2 commits July 29, 2026 05:40
…s survive a shell-driven session
Two reports from the same screenshot, two unrelated causes.
1. "A CONSTANT ERROR NOT GOING AWAY EVEN THOUGH MY SESSION IS PROGRESSING."
The shell row's label chain was `command ?? title ?? description`. A PENDING
bash part has no `input.command` yet, so it fell through to the model's
free-text description and rendered a full prose sentence in the slot where
users read a command — for the command's whole duration (1m55s observed).
The text was a paraphrase of agent guidance: "A local launch is REFUSED by
amico-run while this solver is selected (exit 64), so attempting one only
wastes a turn." Nothing had failed. The solve underneath was on iteration 29
with frames on disk, and the solver was `piccolo`, so the sentence was not
even applicable.
The description fallback is worth keeping (often a useful "Install deps"), so
the fix is not to drop it but to stop it impersonating a command: unwrap
quotes, first line only, clamp to 72 chars with an ellipsis. Prose can no
longer fill the row.
2. "WHAT HAPPENED TO THE CHIPS AT THE TOP."
The rail's session gate was `part.tool.startsWith("amicode_")`, so a session
that did its amicode work through the SHELL showed no chips at all. Observed
the same session create a problem workspace, write a solvespec, and drive a
solve to iteration 29 — entirely via bash and amico-run — with the rail hidden
the whole time. It had real entities to describe and refused to.
The gate now also matches a shell part whose command drives amicode
(`amico-run`, `.amico/problems`, `amico plan|spec`). It stays SESSION-scoped,
which is the point of the gate — an unrelated session still shows nothing, and
there is a test pinning that.
The refetch key is deliberately NOT broadened: shell parts don't mutate the
problem view through the tool seam, so counting them would refetch on
unrelated shell activity.
Both rules are extracted to pure modules (rail-gate.ts, shell-row.ts) because
neither was testable inside its .tsx and both shipped a user-visible bug. 15 new
tests; ui suite 318 pass; tsgo clean in ui and app.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Reported right after the chips: "where did the little amico icon go, why is that
not active anymore?"
Same cause. The working-presence lane (the pulsing H-mark + thinking line) gated
on its own copy of the amicode_* tool-name test:
p.type === "tool" && /^amicode_/.test(p.tool)
identical in spirit to the rail's gate, and duplicated. So a session that did its
amicode work through the SHELL lost the chips and Amico's presence together — the
mark read as "inactive" while a solve was running at iteration 29.
It now calls sessionHasAmicodeParts, so there is ONE definition of "this session
is amicode work" and one place to widen it. Behaviour for tool-driven sessions is
unchanged; shell-driven sessions get their presence back.
Worth noting this was the third symptom of a single assumption — that amicode work
always arrives as an amicode_* tool part. Chips, presence mark, and (indirectly)
the missing telemetry all traced to it.
ui 318 pass; tsgo clean in ui and app.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@Rchari1
Rchari1force-pushed the rchari/chat-row-and-rail-gate branch from 3c4e6fc to c138994CompareJuly 29, 2026 09:54
@jack-champagne
jack-champagne merged commit 3a1f6b9 into local/amicodeJul 29, 2026
3 of 5 checks passed
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@Rchari1@jack-champagne
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

fix(chat): pending shell row stops impersonating an error; chips survive a shell-driven session - #99

Merged
jack-champagne merged 2 commits into
local/amicodefrom
rchari/chat-row-and-rail-gate
Jul 29, 2026
Merged

fix(chat): pending shell row stops impersonating an error; chips survive a shell-driven session#99
jack-champagne merged 2 commits into
local/amicodefrom
rchari/chat-row-and-rail-gate

Conversation

@Rchari1

Copy link
Copy Markdown
Member

Two reports from the same screenshot, two unrelated causes. Both were untestable where they lived, and both shipped a user-visible bug, so each rule is extracted to a pure module with tests.

1. "A constant error not going away even though my session is progressing"

The shell row's label chain was command ?? title ?? description. A pending bash part has no input.command yet, so it fell through to the model's free-text description and rendered a full prose sentence in the slot where users read a command — and held it for the command's whole duration (1m55s observed).

The text was a paraphrase of agent guidance:

"A local launch is REFUSED by amico-run while this solver is selected (exit 64), so attempting one only wastes a turn."

Nothing had failed. The solve underneath was on iteration 29 with frames on disk, and the solver was piccolo, so the sentence wasn't even applicable. It just looked exactly like a hard error that wouldn't clear.

The description fallback is worth keeping — it's often a useful "Install deps" — so the fix isn't to drop it but to stop it impersonating a command: unwrap quotes, first line only, clamp to 72 chars with an ellipsis.

2. "What happened to the chips at the top"

The rail's session gate was part.tool.startsWith("amicode_"). A session that did its amicode work through the shell therefore showed no chips at all.

That's what happened here: the same session created a problem workspace, wrote a solvespec.json, and drove a solve to iteration 29 — entirely via bash + amico-run, never calling an amicode_* tool. The rail stayed hidden the whole time despite having real entities to describe.

The gate now also matches a shell part whose command drives amicode (amico-run, .amico/problems, amico plan|spec). It stays session-scoped, which is the entire point of the gate — an unrelated session still shows nothing, and there's a test pinning that.

The refetch key is deliberately not broadened. Shell parts don't mutate the problem view through the tool seam, so counting them would refetch the problem on unrelated shell activity. any (the gate) widens; completed (the refetch key) doesn't.

Testing

15 new tests, including the exact reported strings as regression cases: the quoted guidance sentence must clamp and lose its quote, and a shell-launched solve must open the gate while git status must not. Plus the fiddly edges — pending parts with no input, empty-string commands not beating a usable description, exact clamp boundaries.

ui: 318 pass. tsgo clean in ui and app. Both fixes verified present in the built darwin-arm64 binary (the clamp constant and the shell markers; symbol names are minified away).

Note

These are UI-only. Neither is deploy-gated — worth saying because the chips in particular looked like they might be fixed by shipping something, and they weren't: the gate was rejecting a legitimate session shape.

Rchari1and others added 2 commits July 29, 2026 05:40
…s survive a shell-driven session
Two reports from the same screenshot, two unrelated causes.
1. "A CONSTANT ERROR NOT GOING AWAY EVEN THOUGH MY SESSION IS PROGRESSING."
The shell row's label chain was `command ?? title ?? description`. A PENDING
bash part has no `input.command` yet, so it fell through to the model's
free-text description and rendered a full prose sentence in the slot where
users read a command — for the command's whole duration (1m55s observed).
The text was a paraphrase of agent guidance: "A local launch is REFUSED by
amico-run while this solver is selected (exit 64), so attempting one only
wastes a turn." Nothing had failed. The solve underneath was on iteration 29
with frames on disk, and the solver was `piccolo`, so the sentence was not
even applicable.
The description fallback is worth keeping (often a useful "Install deps"), so
the fix is not to drop it but to stop it impersonating a command: unwrap
quotes, first line only, clamp to 72 chars with an ellipsis. Prose can no
longer fill the row.
2. "WHAT HAPPENED TO THE CHIPS AT THE TOP."
The rail's session gate was `part.tool.startsWith("amicode_")`, so a session
that did its amicode work through the SHELL showed no chips at all. Observed
the same session create a problem workspace, write a solvespec, and drive a
solve to iteration 29 — entirely via bash and amico-run — with the rail hidden
the whole time. It had real entities to describe and refused to.
The gate now also matches a shell part whose command drives amicode
(`amico-run`, `.amico/problems`, `amico plan|spec`). It stays SESSION-scoped,
which is the point of the gate — an unrelated session still shows nothing, and
there is a test pinning that.
The refetch key is deliberately NOT broadened: shell parts don't mutate the
problem view through the tool seam, so counting them would refetch on
unrelated shell activity.
Both rules are extracted to pure modules (rail-gate.ts, shell-row.ts) because
neither was testable inside its .tsx and both shipped a user-visible bug. 15 new
tests; ui suite 318 pass; tsgo clean in ui and app.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Reported right after the chips: "where did the little amico icon go, why is that
not active anymore?"
Same cause. The working-presence lane (the pulsing H-mark + thinking line) gated
on its own copy of the amicode_* tool-name test:
p.type === "tool" && /^amicode_/.test(p.tool)
identical in spirit to the rail's gate, and duplicated. So a session that did its
amicode work through the SHELL lost the chips and Amico's presence together — the
mark read as "inactive" while a solve was running at iteration 29.
It now calls sessionHasAmicodeParts, so there is ONE definition of "this session
is amicode work" and one place to widen it. Behaviour for tool-driven sessions is
unchanged; shell-driven sessions get their presence back.
Worth noting this was the third symptom of a single assumption — that amicode work
always arrives as an amicode_* tool part. Chips, presence mark, and (indirectly)
the missing telemetry all traced to it.
ui 318 pass; tsgo clean in ui and app.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@Rchari1
Rchari1force-pushed the rchari/chat-row-and-rail-gate branch from 3c4e6fc to c138994CompareJuly 29, 2026 09:54
@jack-champagne
jack-champagne merged commit 3a1f6b9 into local/amicodeJul 29, 2026
3 of 5 checks passed
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@Rchari1@jack-champagne
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

fix(chat): pending shell row stops impersonating an error; chips survive a shell-driven session - #99

Merged
jack-champagne merged 2 commits into
local/amicodefrom
rchari/chat-row-and-rail-gate
Jul 29, 2026
Merged

fix(chat): pending shell row stops impersonating an error; chips survive a shell-driven session#99
jack-champagne merged 2 commits into
local/amicodefrom
rchari/chat-row-and-rail-gate

Conversation

@Rchari1

Copy link
Copy Markdown
Member

Two reports from the same screenshot, two unrelated causes. Both were untestable where they lived, and both shipped a user-visible bug, so each rule is extracted to a pure module with tests.

1. "A constant error not going away even though my session is progressing"

The shell row's label chain was command ?? title ?? description. A pending bash part has no input.command yet, so it fell through to the model's free-text description and rendered a full prose sentence in the slot where users read a command — and held it for the command's whole duration (1m55s observed).

The text was a paraphrase of agent guidance:

"A local launch is REFUSED by amico-run while this solver is selected (exit 64), so attempting one only wastes a turn."

Nothing had failed. The solve underneath was on iteration 29 with frames on disk, and the solver was piccolo, so the sentence wasn't even applicable. It just looked exactly like a hard error that wouldn't clear.

The description fallback is worth keeping — it's often a useful "Install deps" — so the fix isn't to drop it but to stop it impersonating a command: unwrap quotes, first line only, clamp to 72 chars with an ellipsis.

2. "What happened to the chips at the top"

The rail's session gate was part.tool.startsWith("amicode_"). A session that did its amicode work through the shell therefore showed no chips at all.

That's what happened here: the same session created a problem workspace, wrote a solvespec.json, and drove a solve to iteration 29 — entirely via bash + amico-run, never calling an amicode_* tool. The rail stayed hidden the whole time despite having real entities to describe.

The gate now also matches a shell part whose command drives amicode (amico-run, .amico/problems, amico plan|spec). It stays session-scoped, which is the entire point of the gate — an unrelated session still shows nothing, and there's a test pinning that.

The refetch key is deliberately not broadened. Shell parts don't mutate the problem view through the tool seam, so counting them would refetch the problem on unrelated shell activity. any (the gate) widens; completed (the refetch key) doesn't.

Testing

15 new tests, including the exact reported strings as regression cases: the quoted guidance sentence must clamp and lose its quote, and a shell-launched solve must open the gate while git status must not. Plus the fiddly edges — pending parts with no input, empty-string commands not beating a usable description, exact clamp boundaries.

ui: 318 pass. tsgo clean in ui and app. Both fixes verified present in the built darwin-arm64 binary (the clamp constant and the shell markers; symbol names are minified away).

Note

These are UI-only. Neither is deploy-gated — worth saying because the chips in particular looked like they might be fixed by shipping something, and they weren't: the gate was rejecting a legitimate session shape.

Rchari1and others added 2 commits July 29, 2026 05:40
…s survive a shell-driven session
Two reports from the same screenshot, two unrelated causes.
1. "A CONSTANT ERROR NOT GOING AWAY EVEN THOUGH MY SESSION IS PROGRESSING."
The shell row's label chain was `command ?? title ?? description`. A PENDING
bash part has no `input.command` yet, so it fell through to the model's
free-text description and rendered a full prose sentence in the slot where
users read a command — for the command's whole duration (1m55s observed).
The text was a paraphrase of agent guidance: "A local launch is REFUSED by
amico-run while this solver is selected (exit 64), so attempting one only
wastes a turn." Nothing had failed. The solve underneath was on iteration 29
with frames on disk, and the solver was `piccolo`, so the sentence was not
even applicable.
The description fallback is worth keeping (often a useful "Install deps"), so
the fix is not to drop it but to stop it impersonating a command: unwrap
quotes, first line only, clamp to 72 chars with an ellipsis. Prose can no
longer fill the row.
2. "WHAT HAPPENED TO THE CHIPS AT THE TOP."
The rail's session gate was `part.tool.startsWith("amicode_")`, so a session
that did its amicode work through the SHELL showed no chips at all. Observed
the same session create a problem workspace, write a solvespec, and drive a
solve to iteration 29 — entirely via bash and amico-run — with the rail hidden
the whole time. It had real entities to describe and refused to.
The gate now also matches a shell part whose command drives amicode
(`amico-run`, `.amico/problems`, `amico plan|spec`). It stays SESSION-scoped,
which is the point of the gate — an unrelated session still shows nothing, and
there is a test pinning that.
The refetch key is deliberately NOT broadened: shell parts don't mutate the
problem view through the tool seam, so counting them would refetch on
unrelated shell activity.
Both rules are extracted to pure modules (rail-gate.ts, shell-row.ts) because
neither was testable inside its .tsx and both shipped a user-visible bug. 15 new
tests; ui suite 318 pass; tsgo clean in ui and app.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Reported right after the chips: "where did the little amico icon go, why is that
not active anymore?"
Same cause. The working-presence lane (the pulsing H-mark + thinking line) gated
on its own copy of the amicode_* tool-name test:
p.type === "tool" && /^amicode_/.test(p.tool)
identical in spirit to the rail's gate, and duplicated. So a session that did its
amicode work through the SHELL lost the chips and Amico's presence together — the
mark read as "inactive" while a solve was running at iteration 29.
It now calls sessionHasAmicodeParts, so there is ONE definition of "this session
is amicode work" and one place to widen it. Behaviour for tool-driven sessions is
unchanged; shell-driven sessions get their presence back.
Worth noting this was the third symptom of a single assumption — that amicode work
always arrives as an amicode_* tool part. Chips, presence mark, and (indirectly)
the missing telemetry all traced to it.
ui 318 pass; tsgo clean in ui and app.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@Rchari1
Rchari1force-pushed the rchari/chat-row-and-rail-gate branch from 3c4e6fc to c138994CompareJuly 29, 2026 09:54
@jack-champagne
jack-champagne merged commit 3a1f6b9 into local/amicodeJul 29, 2026
3 of 5 checks passed
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@Rchari1@jack-champagne
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

fix(chat): pending shell row stops impersonating an error; chips survive a shell-driven session - #99

Merged
jack-champagne merged 2 commits into
local/amicodefrom
rchari/chat-row-and-rail-gate
Jul 29, 2026
Merged

fix(chat): pending shell row stops impersonating an error; chips survive a shell-driven session#99
jack-champagne merged 2 commits into
local/amicodefrom
rchari/chat-row-and-rail-gate

Conversation

@Rchari1

Copy link
Copy Markdown
Member

Two reports from the same screenshot, two unrelated causes. Both were untestable where they lived, and both shipped a user-visible bug, so each rule is extracted to a pure module with tests.

1. "A constant error not going away even though my session is progressing"

The shell row's label chain was command ?? title ?? description. A pending bash part has no input.command yet, so it fell through to the model's free-text description and rendered a full prose sentence in the slot where users read a command — and held it for the command's whole duration (1m55s observed).

The text was a paraphrase of agent guidance:

"A local launch is REFUSED by amico-run while this solver is selected (exit 64), so attempting one only wastes a turn."

Nothing had failed. The solve underneath was on iteration 29 with frames on disk, and the solver was piccolo, so the sentence wasn't even applicable. It just looked exactly like a hard error that wouldn't clear.

The description fallback is worth keeping — it's often a useful "Install deps" — so the fix isn't to drop it but to stop it impersonating a command: unwrap quotes, first line only, clamp to 72 chars with an ellipsis.

2. "What happened to the chips at the top"

The rail's session gate was part.tool.startsWith("amicode_"). A session that did its amicode work through the shell therefore showed no chips at all.

That's what happened here: the same session created a problem workspace, wrote a solvespec.json, and drove a solve to iteration 29 — entirely via bash + amico-run, never calling an amicode_* tool. The rail stayed hidden the whole time despite having real entities to describe.

The gate now also matches a shell part whose command drives amicode (amico-run, .amico/problems, amico plan|spec). It stays session-scoped, which is the entire point of the gate — an unrelated session still shows nothing, and there's a test pinning that.

The refetch key is deliberately not broadened. Shell parts don't mutate the problem view through the tool seam, so counting them would refetch the problem on unrelated shell activity. any (the gate) widens; completed (the refetch key) doesn't.

Testing

15 new tests, including the exact reported strings as regression cases: the quoted guidance sentence must clamp and lose its quote, and a shell-launched solve must open the gate while git status must not. Plus the fiddly edges — pending parts with no input, empty-string commands not beating a usable description, exact clamp boundaries.

ui: 318 pass. tsgo clean in ui and app. Both fixes verified present in the built darwin-arm64 binary (the clamp constant and the shell markers; symbol names are minified away).

Note

These are UI-only. Neither is deploy-gated — worth saying because the chips in particular looked like they might be fixed by shipping something, and they weren't: the gate was rejecting a legitimate session shape.

Rchari1and others added 2 commits July 29, 2026 05:40
…s survive a shell-driven session
Two reports from the same screenshot, two unrelated causes.
1. "A CONSTANT ERROR NOT GOING AWAY EVEN THOUGH MY SESSION IS PROGRESSING."
The shell row's label chain was `command ?? title ?? description`. A PENDING
bash part has no `input.command` yet, so it fell through to the model's
free-text description and rendered a full prose sentence in the slot where
users read a command — for the command's whole duration (1m55s observed).
The text was a paraphrase of agent guidance: "A local launch is REFUSED by
amico-run while this solver is selected (exit 64), so attempting one only
wastes a turn." Nothing had failed. The solve underneath was on iteration 29
with frames on disk, and the solver was `piccolo`, so the sentence was not
even applicable.
The description fallback is worth keeping (often a useful "Install deps"), so
the fix is not to drop it but to stop it impersonating a command: unwrap
quotes, first line only, clamp to 72 chars with an ellipsis. Prose can no
longer fill the row.
2. "WHAT HAPPENED TO THE CHIPS AT THE TOP."
The rail's session gate was `part.tool.startsWith("amicode_")`, so a session
that did its amicode work through the SHELL showed no chips at all. Observed
the same session create a problem workspace, write a solvespec, and drive a
solve to iteration 29 — entirely via bash and amico-run — with the rail hidden
the whole time. It had real entities to describe and refused to.
The gate now also matches a shell part whose command drives amicode
(`amico-run`, `.amico/problems`, `amico plan|spec`). It stays SESSION-scoped,
which is the point of the gate — an unrelated session still shows nothing, and
there is a test pinning that.
The refetch key is deliberately NOT broadened: shell parts don't mutate the
problem view through the tool seam, so counting them would refetch on
unrelated shell activity.
Both rules are extracted to pure modules (rail-gate.ts, shell-row.ts) because
neither was testable inside its .tsx and both shipped a user-visible bug. 15 new
tests; ui suite 318 pass; tsgo clean in ui and app.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Reported right after the chips: "where did the little amico icon go, why is that
not active anymore?"
Same cause. The working-presence lane (the pulsing H-mark + thinking line) gated
on its own copy of the amicode_* tool-name test:
p.type === "tool" && /^amicode_/.test(p.tool)
identical in spirit to the rail's gate, and duplicated. So a session that did its
amicode work through the SHELL lost the chips and Amico's presence together — the
mark read as "inactive" while a solve was running at iteration 29.
It now calls sessionHasAmicodeParts, so there is ONE definition of "this session
is amicode work" and one place to widen it. Behaviour for tool-driven sessions is
unchanged; shell-driven sessions get their presence back.
Worth noting this was the third symptom of a single assumption — that amicode work
always arrives as an amicode_* tool part. Chips, presence mark, and (indirectly)
the missing telemetry all traced to it.
ui 318 pass; tsgo clean in ui and app.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@Rchari1
Rchari1force-pushed the rchari/chat-row-and-rail-gate branch from 3c4e6fc to c138994CompareJuly 29, 2026 09:54
@jack-champagne
jack-champagne merged commit 3a1f6b9 into local/amicodeJul 29, 2026
3 of 5 checks passed
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@Rchari1@jack-champagne
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

fix(chat): pending shell row stops impersonating an error; chips survive a shell-driven session - #99

Merged
jack-champagne merged 2 commits into
local/amicodefrom
rchari/chat-row-and-rail-gate
Jul 29, 2026
Merged

fix(chat): pending shell row stops impersonating an error; chips survive a shell-driven session#99
jack-champagne merged 2 commits into
local/amicodefrom
rchari/chat-row-and-rail-gate

Conversation

@Rchari1

Copy link
Copy Markdown
Member

Two reports from the same screenshot, two unrelated causes. Both were untestable where they lived, and both shipped a user-visible bug, so each rule is extracted to a pure module with tests.

1. "A constant error not going away even though my session is progressing"

The shell row's label chain was command ?? title ?? description. A pending bash part has no input.command yet, so it fell through to the model's free-text description and rendered a full prose sentence in the slot where users read a command — and held it for the command's whole duration (1m55s observed).

The text was a paraphrase of agent guidance:

"A local launch is REFUSED by amico-run while this solver is selected (exit 64), so attempting one only wastes a turn."

Nothing had failed. The solve underneath was on iteration 29 with frames on disk, and the solver was piccolo, so the sentence wasn't even applicable. It just looked exactly like a hard error that wouldn't clear.

The description fallback is worth keeping — it's often a useful "Install deps" — so the fix isn't to drop it but to stop it impersonating a command: unwrap quotes, first line only, clamp to 72 chars with an ellipsis.

2. "What happened to the chips at the top"

The rail's session gate was part.tool.startsWith("amicode_"). A session that did its amicode work through the shell therefore showed no chips at all.

That's what happened here: the same session created a problem workspace, wrote a solvespec.json, and drove a solve to iteration 29 — entirely via bash + amico-run, never calling an amicode_* tool. The rail stayed hidden the whole time despite having real entities to describe.

The gate now also matches a shell part whose command drives amicode (amico-run, .amico/problems, amico plan|spec). It stays session-scoped, which is the entire point of the gate — an unrelated session still shows nothing, and there's a test pinning that.

The refetch key is deliberately not broadened. Shell parts don't mutate the problem view through the tool seam, so counting them would refetch the problem on unrelated shell activity. any (the gate) widens; completed (the refetch key) doesn't.

Testing

15 new tests, including the exact reported strings as regression cases: the quoted guidance sentence must clamp and lose its quote, and a shell-launched solve must open the gate while git status must not. Plus the fiddly edges — pending parts with no input, empty-string commands not beating a usable description, exact clamp boundaries.

ui: 318 pass. tsgo clean in ui and app. Both fixes verified present in the built darwin-arm64 binary (the clamp constant and the shell markers; symbol names are minified away).

Note

These are UI-only. Neither is deploy-gated — worth saying because the chips in particular looked like they might be fixed by shipping something, and they weren't: the gate was rejecting a legitimate session shape.

Rchari1and others added 2 commits July 29, 2026 05:40
…s survive a shell-driven session
Two reports from the same screenshot, two unrelated causes.
1. "A CONSTANT ERROR NOT GOING AWAY EVEN THOUGH MY SESSION IS PROGRESSING."
The shell row's label chain was `command ?? title ?? description`. A PENDING
bash part has no `input.command` yet, so it fell through to the model's
free-text description and rendered a full prose sentence in the slot where
users read a command — for the command's whole duration (1m55s observed).
The text was a paraphrase of agent guidance: "A local launch is REFUSED by
amico-run while this solver is selected (exit 64), so attempting one only
wastes a turn." Nothing had failed. The solve underneath was on iteration 29
with frames on disk, and the solver was `piccolo`, so the sentence was not
even applicable.
The description fallback is worth keeping (often a useful "Install deps"), so
the fix is not to drop it but to stop it impersonating a command: unwrap
quotes, first line only, clamp to 72 chars with an ellipsis. Prose can no
longer fill the row.
2. "WHAT HAPPENED TO THE CHIPS AT THE TOP."
The rail's session gate was `part.tool.startsWith("amicode_")`, so a session
that did its amicode work through the SHELL showed no chips at all. Observed
the same session create a problem workspace, write a solvespec, and drive a
solve to iteration 29 — entirely via bash and amico-run — with the rail hidden
the whole time. It had real entities to describe and refused to.
The gate now also matches a shell part whose command drives amicode
(`amico-run`, `.amico/problems`, `amico plan|spec`). It stays SESSION-scoped,
which is the point of the gate — an unrelated session still shows nothing, and
there is a test pinning that.
The refetch key is deliberately NOT broadened: shell parts don't mutate the
problem view through the tool seam, so counting them would refetch on
unrelated shell activity.
Both rules are extracted to pure modules (rail-gate.ts, shell-row.ts) because
neither was testable inside its .tsx and both shipped a user-visible bug. 15 new
tests; ui suite 318 pass; tsgo clean in ui and app.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Reported right after the chips: "where did the little amico icon go, why is that
not active anymore?"
Same cause. The working-presence lane (the pulsing H-mark + thinking line) gated
on its own copy of the amicode_* tool-name test:
p.type === "tool" && /^amicode_/.test(p.tool)
identical in spirit to the rail's gate, and duplicated. So a session that did its
amicode work through the SHELL lost the chips and Amico's presence together — the
mark read as "inactive" while a solve was running at iteration 29.
It now calls sessionHasAmicodeParts, so there is ONE definition of "this session
is amicode work" and one place to widen it. Behaviour for tool-driven sessions is
unchanged; shell-driven sessions get their presence back.
Worth noting this was the third symptom of a single assumption — that amicode work
always arrives as an amicode_* tool part. Chips, presence mark, and (indirectly)
the missing telemetry all traced to it.
ui 318 pass; tsgo clean in ui and app.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@Rchari1
Rchari1force-pushed the rchari/chat-row-and-rail-gate branch from 3c4e6fc to c138994CompareJuly 29, 2026 09:54
@jack-champagne
jack-champagne merged commit 3a1f6b9 into local/amicodeJul 29, 2026
3 of 5 checks passed
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@Rchari1@jack-champagne
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

fix(chat): pending shell row stops impersonating an error; chips survive a shell-driven session - #99

Merged
jack-champagne merged 2 commits into
local/amicodefrom
rchari/chat-row-and-rail-gate
Jul 29, 2026
Merged

fix(chat): pending shell row stops impersonating an error; chips survive a shell-driven session#99
jack-champagne merged 2 commits into
local/amicodefrom
rchari/chat-row-and-rail-gate

Conversation

@Rchari1

Copy link
Copy Markdown
Member

Two reports from the same screenshot, two unrelated causes. Both were untestable where they lived, and both shipped a user-visible bug, so each rule is extracted to a pure module with tests.

1. "A constant error not going away even though my session is progressing"

The shell row's label chain was command ?? title ?? description. A pending bash part has no input.command yet, so it fell through to the model's free-text description and rendered a full prose sentence in the slot where users read a command — and held it for the command's whole duration (1m55s observed).

The text was a paraphrase of agent guidance:

"A local launch is REFUSED by amico-run while this solver is selected (exit 64), so attempting one only wastes a turn."

Nothing had failed. The solve underneath was on iteration 29 with frames on disk, and the solver was piccolo, so the sentence wasn't even applicable. It just looked exactly like a hard error that wouldn't clear.

The description fallback is worth keeping — it's often a useful "Install deps" — so the fix isn't to drop it but to stop it impersonating a command: unwrap quotes, first line only, clamp to 72 chars with an ellipsis.

2. "What happened to the chips at the top"

The rail's session gate was part.tool.startsWith("amicode_"). A session that did its amicode work through the shell therefore showed no chips at all.

That's what happened here: the same session created a problem workspace, wrote a solvespec.json, and drove a solve to iteration 29 — entirely via bash + amico-run, never calling an amicode_* tool. The rail stayed hidden the whole time despite having real entities to describe.

The gate now also matches a shell part whose command drives amicode (amico-run, .amico/problems, amico plan|spec). It stays session-scoped, which is the entire point of the gate — an unrelated session still shows nothing, and there's a test pinning that.

The refetch key is deliberately not broadened. Shell parts don't mutate the problem view through the tool seam, so counting them would refetch the problem on unrelated shell activity. any (the gate) widens; completed (the refetch key) doesn't.

Testing

15 new tests, including the exact reported strings as regression cases: the quoted guidance sentence must clamp and lose its quote, and a shell-launched solve must open the gate while git status must not. Plus the fiddly edges — pending parts with no input, empty-string commands not beating a usable description, exact clamp boundaries.

ui: 318 pass. tsgo clean in ui and app. Both fixes verified present in the built darwin-arm64 binary (the clamp constant and the shell markers; symbol names are minified away).

Note

These are UI-only. Neither is deploy-gated — worth saying because the chips in particular looked like they might be fixed by shipping something, and they weren't: the gate was rejecting a legitimate session shape.

Rchari1and others added 2 commits July 29, 2026 05:40
…s survive a shell-driven session
Two reports from the same screenshot, two unrelated causes.
1. "A CONSTANT ERROR NOT GOING AWAY EVEN THOUGH MY SESSION IS PROGRESSING."
The shell row's label chain was `command ?? title ?? description`. A PENDING
bash part has no `input.command` yet, so it fell through to the model's
free-text description and rendered a full prose sentence in the slot where
users read a command — for the command's whole duration (1m55s observed).
The text was a paraphrase of agent guidance: "A local launch is REFUSED by
amico-run while this solver is selected (exit 64), so attempting one only
wastes a turn." Nothing had failed. The solve underneath was on iteration 29
with frames on disk, and the solver was `piccolo`, so the sentence was not
even applicable.
The description fallback is worth keeping (often a useful "Install deps"), so
the fix is not to drop it but to stop it impersonating a command: unwrap
quotes, first line only, clamp to 72 chars with an ellipsis. Prose can no
longer fill the row.
2. "WHAT HAPPENED TO THE CHIPS AT THE TOP."
The rail's session gate was `part.tool.startsWith("amicode_")`, so a session
that did its amicode work through the SHELL showed no chips at all. Observed
the same session create a problem workspace, write a solvespec, and drive a
solve to iteration 29 — entirely via bash and amico-run — with the rail hidden
the whole time. It had real entities to describe and refused to.
The gate now also matches a shell part whose command drives amicode
(`amico-run`, `.amico/problems`, `amico plan|spec`). It stays SESSION-scoped,
which is the point of the gate — an unrelated session still shows nothing, and
there is a test pinning that.
The refetch key is deliberately NOT broadened: shell parts don't mutate the
problem view through the tool seam, so counting them would refetch on
unrelated shell activity.
Both rules are extracted to pure modules (rail-gate.ts, shell-row.ts) because
neither was testable inside its .tsx and both shipped a user-visible bug. 15 new
tests; ui suite 318 pass; tsgo clean in ui and app.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Reported right after the chips: "where did the little amico icon go, why is that
not active anymore?"
Same cause. The working-presence lane (the pulsing H-mark + thinking line) gated
on its own copy of the amicode_* tool-name test:
p.type === "tool" && /^amicode_/.test(p.tool)
identical in spirit to the rail's gate, and duplicated. So a session that did its
amicode work through the SHELL lost the chips and Amico's presence together — the
mark read as "inactive" while a solve was running at iteration 29.
It now calls sessionHasAmicodeParts, so there is ONE definition of "this session
is amicode work" and one place to widen it. Behaviour for tool-driven sessions is
unchanged; shell-driven sessions get their presence back.
Worth noting this was the third symptom of a single assumption — that amicode work
always arrives as an amicode_* tool part. Chips, presence mark, and (indirectly)
the missing telemetry all traced to it.
ui 318 pass; tsgo clean in ui and app.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@Rchari1
Rchari1force-pushed the rchari/chat-row-and-rail-gate branch from 3c4e6fc to c138994CompareJuly 29, 2026 09:54
@jack-champagne
jack-champagne merged commit 3a1f6b9 into local/amicodeJul 29, 2026
3 of 5 checks passed
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@Rchari1@jack-champagne
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

fix(chat): pending shell row stops impersonating an error; chips survive a shell-driven session - #99

Merged
jack-champagne merged 2 commits into
local/amicodefrom
rchari/chat-row-and-rail-gate
Jul 29, 2026
Merged

fix(chat): pending shell row stops impersonating an error; chips survive a shell-driven session#99
jack-champagne merged 2 commits into
local/amicodefrom
rchari/chat-row-and-rail-gate

Conversation

@Rchari1

Copy link
Copy Markdown
Member

Two reports from the same screenshot, two unrelated causes. Both were untestable where they lived, and both shipped a user-visible bug, so each rule is extracted to a pure module with tests.

1. "A constant error not going away even though my session is progressing"

The shell row's label chain was command ?? title ?? description. A pending bash part has no input.command yet, so it fell through to the model's free-text description and rendered a full prose sentence in the slot where users read a command — and held it for the command's whole duration (1m55s observed).

The text was a paraphrase of agent guidance:

"A local launch is REFUSED by amico-run while this solver is selected (exit 64), so attempting one only wastes a turn."

Nothing had failed. The solve underneath was on iteration 29 with frames on disk, and the solver was piccolo, so the sentence wasn't even applicable. It just looked exactly like a hard error that wouldn't clear.

The description fallback is worth keeping — it's often a useful "Install deps" — so the fix isn't to drop it but to stop it impersonating a command: unwrap quotes, first line only, clamp to 72 chars with an ellipsis.

2. "What happened to the chips at the top"

The rail's session gate was part.tool.startsWith("amicode_"). A session that did its amicode work through the shell therefore showed no chips at all.

That's what happened here: the same session created a problem workspace, wrote a solvespec.json, and drove a solve to iteration 29 — entirely via bash + amico-run, never calling an amicode_* tool. The rail stayed hidden the whole time despite having real entities to describe.

The gate now also matches a shell part whose command drives amicode (amico-run, .amico/problems, amico plan|spec). It stays session-scoped, which is the entire point of the gate — an unrelated session still shows nothing, and there's a test pinning that.

The refetch key is deliberately not broadened. Shell parts don't mutate the problem view through the tool seam, so counting them would refetch the problem on unrelated shell activity. any (the gate) widens; completed (the refetch key) doesn't.

Testing

15 new tests, including the exact reported strings as regression cases: the quoted guidance sentence must clamp and lose its quote, and a shell-launched solve must open the gate while git status must not. Plus the fiddly edges — pending parts with no input, empty-string commands not beating a usable description, exact clamp boundaries.

ui: 318 pass. tsgo clean in ui and app. Both fixes verified present in the built darwin-arm64 binary (the clamp constant and the shell markers; symbol names are minified away).

Note

These are UI-only. Neither is deploy-gated — worth saying because the chips in particular looked like they might be fixed by shipping something, and they weren't: the gate was rejecting a legitimate session shape.

Rchari1and others added 2 commits July 29, 2026 05:40
…s survive a shell-driven session
Two reports from the same screenshot, two unrelated causes.
1. "A CONSTANT ERROR NOT GOING AWAY EVEN THOUGH MY SESSION IS PROGRESSING."
The shell row's label chain was `command ?? title ?? description`. A PENDING
bash part has no `input.command` yet, so it fell through to the model's
free-text description and rendered a full prose sentence in the slot where
users read a command — for the command's whole duration (1m55s observed).
The text was a paraphrase of agent guidance: "A local launch is REFUSED by
amico-run while this solver is selected (exit 64), so attempting one only
wastes a turn." Nothing had failed. The solve underneath was on iteration 29
with frames on disk, and the solver was `piccolo`, so the sentence was not
even applicable.
The description fallback is worth keeping (often a useful "Install deps"), so
the fix is not to drop it but to stop it impersonating a command: unwrap
quotes, first line only, clamp to 72 chars with an ellipsis. Prose can no
longer fill the row.
2. "WHAT HAPPENED TO THE CHIPS AT THE TOP."
The rail's session gate was `part.tool.startsWith("amicode_")`, so a session
that did its amicode work through the SHELL showed no chips at all. Observed
the same session create a problem workspace, write a solvespec, and drive a
solve to iteration 29 — entirely via bash and amico-run — with the rail hidden
the whole time. It had real entities to describe and refused to.
The gate now also matches a shell part whose command drives amicode
(`amico-run`, `.amico/problems`, `amico plan|spec`). It stays SESSION-scoped,
which is the point of the gate — an unrelated session still shows nothing, and
there is a test pinning that.
The refetch key is deliberately NOT broadened: shell parts don't mutate the
problem view through the tool seam, so counting them would refetch on
unrelated shell activity.
Both rules are extracted to pure modules (rail-gate.ts, shell-row.ts) because
neither was testable inside its .tsx and both shipped a user-visible bug. 15 new
tests; ui suite 318 pass; tsgo clean in ui and app.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Reported right after the chips: "where did the little amico icon go, why is that
not active anymore?"
Same cause. The working-presence lane (the pulsing H-mark + thinking line) gated
on its own copy of the amicode_* tool-name test:
p.type === "tool" && /^amicode_/.test(p.tool)
identical in spirit to the rail's gate, and duplicated. So a session that did its
amicode work through the SHELL lost the chips and Amico's presence together — the
mark read as "inactive" while a solve was running at iteration 29.
It now calls sessionHasAmicodeParts, so there is ONE definition of "this session
is amicode work" and one place to widen it. Behaviour for tool-driven sessions is
unchanged; shell-driven sessions get their presence back.
Worth noting this was the third symptom of a single assumption — that amicode work
always arrives as an amicode_* tool part. Chips, presence mark, and (indirectly)
the missing telemetry all traced to it.
ui 318 pass; tsgo clean in ui and app.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@Rchari1
Rchari1force-pushed the rchari/chat-row-and-rail-gate branch from 3c4e6fc to c138994CompareJuly 29, 2026 09:54
@jack-champagne
jack-champagne merged commit 3a1f6b9 into local/amicodeJul 29, 2026
3 of 5 checks passed
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@Rchari1@jack-champagne
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

fix(chat): pending shell row stops impersonating an error; chips survive a shell-driven session - #99

Merged
jack-champagne merged 2 commits into
local/amicodefrom
rchari/chat-row-and-rail-gate
Jul 29, 2026
Merged

fix(chat): pending shell row stops impersonating an error; chips survive a shell-driven session#99
jack-champagne merged 2 commits into
local/amicodefrom
rchari/chat-row-and-rail-gate

Conversation

@Rchari1

Copy link
Copy Markdown
Member

Two reports from the same screenshot, two unrelated causes. Both were untestable where they lived, and both shipped a user-visible bug, so each rule is extracted to a pure module with tests.

1. "A constant error not going away even though my session is progressing"

The shell row's label chain was command ?? title ?? description. A pending bash part has no input.command yet, so it fell through to the model's free-text description and rendered a full prose sentence in the slot where users read a command — and held it for the command's whole duration (1m55s observed).

The text was a paraphrase of agent guidance:

"A local launch is REFUSED by amico-run while this solver is selected (exit 64), so attempting one only wastes a turn."

Nothing had failed. The solve underneath was on iteration 29 with frames on disk, and the solver was piccolo, so the sentence wasn't even applicable. It just looked exactly like a hard error that wouldn't clear.

The description fallback is worth keeping — it's often a useful "Install deps" — so the fix isn't to drop it but to stop it impersonating a command: unwrap quotes, first line only, clamp to 72 chars with an ellipsis.

2. "What happened to the chips at the top"

The rail's session gate was part.tool.startsWith("amicode_"). A session that did its amicode work through the shell therefore showed no chips at all.

That's what happened here: the same session created a problem workspace, wrote a solvespec.json, and drove a solve to iteration 29 — entirely via bash + amico-run, never calling an amicode_* tool. The rail stayed hidden the whole time despite having real entities to describe.

The gate now also matches a shell part whose command drives amicode (amico-run, .amico/problems, amico plan|spec). It stays session-scoped, which is the entire point of the gate — an unrelated session still shows nothing, and there's a test pinning that.

The refetch key is deliberately not broadened. Shell parts don't mutate the problem view through the tool seam, so counting them would refetch the problem on unrelated shell activity. any (the gate) widens; completed (the refetch key) doesn't.

Testing

15 new tests, including the exact reported strings as regression cases: the quoted guidance sentence must clamp and lose its quote, and a shell-launched solve must open the gate while git status must not. Plus the fiddly edges — pending parts with no input, empty-string commands not beating a usable description, exact clamp boundaries.

ui: 318 pass. tsgo clean in ui and app. Both fixes verified present in the built darwin-arm64 binary (the clamp constant and the shell markers; symbol names are minified away).

Note

These are UI-only. Neither is deploy-gated — worth saying because the chips in particular looked like they might be fixed by shipping something, and they weren't: the gate was rejecting a legitimate session shape.

Rchari1and others added 2 commits July 29, 2026 05:40
…s survive a shell-driven session
Two reports from the same screenshot, two unrelated causes.
1. "A CONSTANT ERROR NOT GOING AWAY EVEN THOUGH MY SESSION IS PROGRESSING."
The shell row's label chain was `command ?? title ?? description`. A PENDING
bash part has no `input.command` yet, so it fell through to the model's
free-text description and rendered a full prose sentence in the slot where
users read a command — for the command's whole duration (1m55s observed).
The text was a paraphrase of agent guidance: "A local launch is REFUSED by
amico-run while this solver is selected (exit 64), so attempting one only
wastes a turn." Nothing had failed. The solve underneath was on iteration 29
with frames on disk, and the solver was `piccolo`, so the sentence was not
even applicable.
The description fallback is worth keeping (often a useful "Install deps"), so
the fix is not to drop it but to stop it impersonating a command: unwrap
quotes, first line only, clamp to 72 chars with an ellipsis. Prose can no
longer fill the row.
2. "WHAT HAPPENED TO THE CHIPS AT THE TOP."
The rail's session gate was `part.tool.startsWith("amicode_")`, so a session
that did its amicode work through the SHELL showed no chips at all. Observed
the same session create a problem workspace, write a solvespec, and drive a
solve to iteration 29 — entirely via bash and amico-run — with the rail hidden
the whole time. It had real entities to describe and refused to.
The gate now also matches a shell part whose command drives amicode
(`amico-run`, `.amico/problems`, `amico plan|spec`). It stays SESSION-scoped,
which is the point of the gate — an unrelated session still shows nothing, and
there is a test pinning that.
The refetch key is deliberately NOT broadened: shell parts don't mutate the
problem view through the tool seam, so counting them would refetch on
unrelated shell activity.
Both rules are extracted to pure modules (rail-gate.ts, shell-row.ts) because
neither was testable inside its .tsx and both shipped a user-visible bug. 15 new
tests; ui suite 318 pass; tsgo clean in ui and app.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Reported right after the chips: "where did the little amico icon go, why is that
not active anymore?"
Same cause. The working-presence lane (the pulsing H-mark + thinking line) gated
on its own copy of the amicode_* tool-name test:
p.type === "tool" && /^amicode_/.test(p.tool)
identical in spirit to the rail's gate, and duplicated. So a session that did its
amicode work through the SHELL lost the chips and Amico's presence together — the
mark read as "inactive" while a solve was running at iteration 29.
It now calls sessionHasAmicodeParts, so there is ONE definition of "this session
is amicode work" and one place to widen it. Behaviour for tool-driven sessions is
unchanged; shell-driven sessions get their presence back.
Worth noting this was the third symptom of a single assumption — that amicode work
always arrives as an amicode_* tool part. Chips, presence mark, and (indirectly)
the missing telemetry all traced to it.
ui 318 pass; tsgo clean in ui and app.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@Rchari1
Rchari1force-pushed the rchari/chat-row-and-rail-gate branch from 3c4e6fc to c138994CompareJuly 29, 2026 09:54
@jack-champagne
jack-champagne merged commit 3a1f6b9 into local/amicodeJul 29, 2026
3 of 5 checks passed
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@Rchari1@jack-champagne