feat(tangent): brief the agent on naming, and on the project its runs belong to - #2792
Draft
camielvs wants to merge 2 commits into
Conversation
🎩 PreviewA preview build has been created at: |
This was referenced Sep 23, 2026
Collaborator
Author
This was referenced Sep 23, 2026
camielvs
force-pushed
the
09-23-feat_let_the_agent_name_the_project_and_session
branch
from
September 23, 2026 20:57
30b3481 to
feba6da
Compare
camielvs
force-pushed
the
09-23-feat_let_the_agent_name_the_project_and_session
branch
from
September 23, 2026 21:54
feba6da to
54a9c09
Compare
camielvs
force-pushed
the
09-22-feat_projects_that_can_be_shared_and_cancelled
branch
from
September 23, 2026 22:01
0847afe to
817fb36
Compare
camielvs
force-pushed
the
09-23-feat_let_the_agent_name_the_project_and_session
branch
from
September 23, 2026 22:02
54a9c09 to
37ebe50
Compare
This was referenced Sep 23, 2026
Draft
camielvs
force-pushed
the
09-22-feat_projects_that_can_be_shared_and_cancelled
branch
from
September 23, 2026 23:00
817fb36 to
cbd78d9
Compare
camielvs
force-pushed
the
09-23-feat_let_the_agent_name_the_project_and_session
branch
2 times, most recently
from
September 23, 2026 23:36
44b87c5 to
637f724
Compare
camielvs
force-pushed
the
09-22-feat_projects_that_can_be_shared_and_cancelled
branch
from
September 23, 2026 23:36
cbd78d9 to
37c0312
Compare
camielvs
force-pushed
the
09-23-feat_let_the_agent_name_the_project_and_session
branch
from
September 23, 2026 23:56
637f724 to
49c87b1
Compare
camielvs
force-pushed
the
09-22-feat_projects_that_can_be_shared_and_cancelled
branch
from
September 23, 2026 23:56
37c0312 to
74c9c32
Compare
A project opened from the dashboard prompt arrived as "Project 7" with a
session called "Session 1" and a pipeline named after the whole request.
Every one of those is a placeholder, and the agent reading the opening
message already knows what the work is about.
The agent now names all three in its first turn, from the first message.
`rename_project`, `name_session` and `name_pipeline` are workarea tools,
and a naming brief is seeded into the session's memory before the agent
spawns, so it is context from the first turn rather than something said
in the transcript.
A name nobody chose is marked as such, and only a marked name may be
replaced: a project or pipeline someone named deliberately is left alone
and the call answers `{ renamed: false }`, which the brief tells the
agent is a final answer rather than something to retry. The mark is
dropped by whoever renames next, agent or human.
Naming a pipeline is the part with real plumbing behind it.
`set_pipeline_name` used to rename the spec held in memory and nothing
else, so the agent reported success while the file stayed "Draft" and
both resource lists kept the name recorded when the pipeline was added.
The spec name is now canonical and everything follows it: the rename goes
through the file first, and the name the file actually took is what the
spec is called — a name already taken comes back adjusted, and the agent
is told so rather than left believing it got the name it asked for. The
open tab retitles instead of announcing the name it had when it opened.
Browser storage fires no event a rename in this tab would reach, and the
query behind those lists is keyed on the pointer, which a rename does not
change — so the rename invalidates it. Without that the new name only
appeared a minute later, or on reload, which read as a silent failure.
`name_pipeline` drives the open tab's bridge rather than the resource
row, because only the bridge moves the spec, the file and the row
together. The editor keeps a fallback rule for a pipeline still unnamed
once its changes are in, and the provisional mark lives on the spec
rather than the resource because the agent that acts on it reads the
canvas and never sees the row.
Both resource lists now ask what a pipeline is called rather than
trusting the copy on the row, which also fixes the same staleness after a
rename from the menu bar. A name-only pointer is trusted only in the
browser that wrote it: someone else's "Churn model" is not the one this
browser holds. `useUnavailablePipelines` moves to `services/projects` as
`useLocalPipelineStatus`, since both pages need it and it answers two
questions rather than one.
A derived name keeps what the ask was about: trimming a dangling
preposition off the end must not amputate the subject with it.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
camielvs
force-pushed
the
09-22-feat_projects_that_can_be_shared_and_cancelled
branch
from
September 24, 2026 00:14
74c9c32 to
e5a678c
Compare
camielvs
force-pushed
the
09-23-feat_let_the_agent_name_the_project_and_session
branch
from
September 24, 2026 00:14
49c87b1 to
4b4380a
Compare
A run reaches a project's feed by carrying an annotation naming the project, written at submit time — there is no run row to attach afterwards, and the key cannot be added later because the endpoint that sets one takes the key as a path segment and rejects this one for its slashes. A run submitted from the browser is attributed already: the scope provider puts the annotation in the submission. An agent submitting from its own sandbox is not, and cannot be: the remote-env handshake carries only the session id, and the workarea tools submit no runs. So the id never reaches the agent that needs it, and the run it starts is filed under nothing. The session's memory seed already briefs the agent before it spawns. It now also carries the project id, the annotation to submit with, and the two limits it would otherwise discover by being refused: one project per run, and never this key on a saved pipeline, whose stored annotations decide its version identity. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.

Problem
A project opened from the dashboard prompt arrived as "Project 7", with a
session called "Session 1" and a pipeline named after the entire request —
Build a pipeline that scrapes wikipedia and converts articles into a pokemon….Every one of those is a placeholder, and the agent reading the opening message
already knows what the work is about.
What changed
The agent names all three in its first turn, from the first message.
rename_project,name_sessionandname_pipelineare workarea tools, and anaming brief is seeded into the session's memory before the agent spawns, so
it is context from turn one rather than something said in the transcript.
Only a name nobody chose may be replaced. A project or pipeline someone
named deliberately is left alone and the call answers
{ renamed: false }—which the brief tells the agent is a final answer, not something to retry. The
mark is dropped by whoever renames next, agent or human.
Naming a pipeline is the part with real plumbing behind it
set_pipeline_nameused to rename the spec held in memory and nothing else, sothe agent reported success while the file stayed
Draftand both resource listskept the name recorded when the pipeline was added.
The spec name is now canonical and everything follows it. The rename goes through
the file first, and the name the file actually took is what the spec is called —
a collision adjusts rather than overwriting, the rule
create_pipelinealreadyfollows, and the agent is told so:
The open tab retitles rather than announcing the name it resolved when it opened.
And the rename now invalidates the query behind the resource lists. Browser
storage fires no event a same-tab rename would reach, and that query is keyed on
the pointer, which a rename does not change. Without this the new name only
appeared a minute later, or on reload — which read as the rename silently
failing.
name_pipelinedrives the open tab's bridge rather than the resource row,because only the bridge moves the spec, the file and the row together. The editor
keeps a fallback rule for a pipeline still unnamed once its changes are in, and
the provisional mark lives on the spec rather than the resource because the agent
that acts on it reads the canvas and never sees the row.
Resource rows stop trusting a stale copy
Both lists ask what a pipeline is called now, which also fixes the same
staleness after a rename from the menu bar. A name-only pointer is trusted only
in the browser that wrote it — someone else's "Churn model" is not the one this
browser holds. Unknown authorship is trusted, which is every single-user backend.
useUnavailablePipelinesmoves toservices/projectsasuseLocalPipelineStatus,since both pages need it and it answers two questions rather than one.
This also meant separating a row's display label from "this row opens a
conversation elsewhere", which had been sharing one prop. A renamed pipeline is
still a row on this page; overloading the label would have made it open as a
session and lose its Remove button.
A derived name also keeps what the ask was about: trimming a dangling preposition
off the end must not amputate the subject with it.
The same seed now tells the agent which project its runs belong to
A run reaches a project's feed by carrying an annotation naming the project,
written at submit time — there is no run row to attach afterwards, and the key
cannot be added later, because the endpoint that sets a single annotation takes
the key as a path segment and rejects this one for its slashes.
A run submitted from the browser is attributed already: the scope provider puts
the annotation in the submission. An agent submitting from its own sandbox is
not, and cannot be — the remote-env handshake carries only the session id, and
the workarea tools submit no runs. So the id never reaches the agent that needs
it, and a run it starts is filed under nothing. That is what was seen on staging:
the agent fell back to building a pipeline outside the canvas, submitted it
itself, and the project reported nothing had been run.
The memory seed already briefs the agent before it spawns, so the project id goes
there, with the annotation to submit with and the two limits it would otherwise
discover by being refused: one project per run, and never this key on a saved
pipeline, whose stored annotations decide its version identity.
The key is built from the same helper the browser submits with, so the two
cannot drift.
This makes the agent aware; it does not make it certain. A brief can be
forgotten on a later turn, and a forgotten tag cannot be repaired. The guarantee
would be for the sandbox's own submit helper to add the annotation from session
context — which needs the id on the wire, and that half is not in this repo.
Note on scope
This absorbs what was PR #2796. Split apart, this PR claimed to name pipelines
while the rename only ever reached the spec in memory — they are one change.
Run attribution rides along because it is the same artifact: one memory seed,
written once before the agent spawns. A second PR would have been a second edit
to the same string.
Testing
pnpm run validateclean;npx vitest run320 files / 3248 tests green.message; the pipeline rename fired and the collision message surfaced, but the
new name only reached the lists on reload — which the query invalidation here
fixes. The first-turn
name_pipelinepath has not been exercised against alive agent yet.
🤖 Generated with Claude Code