Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 0 additions & 6 deletions .changeset/plan-agents-label.md

This file was deleted.

6 changes: 0 additions & 6 deletions .changeset/planner-owned-agent-creation.md

This file was deleted.

19 changes: 10 additions & 9 deletions .changeset/unified-project-agents.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,19 +8,20 @@ Unify Agent Studio project sessions around one ordinary coding-agent identity, m
**Breaking for embedders** (minor while `@sapiom/harness` is pre-1.0):
`HarnessSession.agentMapIdentity` is now the role-neutral
`ProjectAgentSession { projectId, userId, sessionId }`; `role` and `assignment`
are no longer present. Valid persisted `planning` metadata is migrated into the
optional `projectBootstrap` lifecycle field and then removed. The deprecated
planner-message alias now returns `ProjectBootstrapMetadata | null`, with
`projectId`, `userId`, `targetSessionId`, and `bootstrap` replacing the former
nested `identity` and `greeting` fields.
are no longer present. Valid persisted pre-upgrade session metadata is migrated
into the optional `projectBootstrap` lifecycle field and then removed. Retired
project-session HTTP aliases and public API names are removed; live clients use
the generic session routes.

**Migration:** stop branching on `agentMapIdentity.role` or `.assignment`, read
optional `projectBootstrap` only for bootstrap status, and handle `metadata:
null` from the compatibility alias—or move to the generic session routes. An
optional `projectBootstrap` only for bootstrap status, and use the generic
session routes. An
embedder that already owns a new session's first prompt should send
`initialUserInputPending: true` in the same `CreateSessionRequest`, so automatic
bootstrap yields before launch. New telemetry consumers should recognize the
neutral `project_agent.*` and `project_bootstrap.*` events. Valid legacy state
keeps its session/provider IDs, cwd, title, transcript, and Canvas; malformed or
conflicting authority is retained and fails closed. Downgrading does not restore
the former planner coordinator semantics.
conflicting authority is retained and fails closed. Released infrastructure
bootstrap event markers remain read-compatible so their private control prompt
never becomes a human transcript turn after upgrade. Downgrading does not
restore the superseded session authority model.
65 changes: 64 additions & 1 deletion .github/workflows/claude-code-review.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,12 @@ name: Claude Code Review
# tarballs, so customer names and internal business context must be caught
# at review time — a static blocklist committed here would itself publish
# the names it protects.
#
# The prompt also carries a frontend component-hygiene section, which is
# ADVISORY by design. We do not gate a build on design parity, so those
# findings inform and never block. It exists because `lint` in the harness
# package is `eslint src`, which does not cover `web/src`, where nearly all
# Studio UI lives: this review is the only automated read of that code.

on:
pull_request:
Expand Down Expand Up @@ -258,6 +264,60 @@ jobs:
a released version — beyond what fixing it inherently reveals — flag that the details
belong in private reporting per SECURITY.md, not in a public PR.

## Frontend component hygiene

**Applies only when the diff touches frontend component code**: `.tsx`/`.css` under
`packages/harness/web/src`, `packages/harness-desktop/src/renderer`, or any other `web/` or
`renderer/` tree. If the diff has none, skip this section and say nothing about it.

**You are the only automated eye on this code.** The harness `lint` script is
`eslint src --ext .ts`, which does not cover `web/src`, where nearly all Studio UI lives. Do
not assume a linter already caught duplication, dead state, or a hand-written token value.

**This is advisory, not a gate.** We do not fail a build because the UI differs from a
design, and nothing in this section is grounds for blocking. Label these findings
`HYGIENE (advisory)` and word each one as the concrete next step the author can take: name
the existing component, hook, token, or class and give its path. If you cannot point at
something that already exists in the repo, it is an opinion, so drop it.

Grep before claiming something is new: `packages/harness/web/src/components` holds 70+
components and the sibling you want usually exists. Report **at most 3**, highest signal
first, from:

1. **A re-implemented shared primitive.** A hand-rolled popover, menu, empty state, or icon
when the repo already ships one (`AnchoredPopover`, `MenuChoice`, `EmptyState`, `Icon`,
and neighbours). Name the existing one and its path. **Dialogs are the exception and you
must know it before flagging one:** the harness has no generic modal component and no
Radix. The shared thing is the idiom, a `modal-backdrop` > `modal` wrapper with
`useDismissable`, used across roughly a dozen files. `SecretDialogShell` is the secrets
dialogs' own shell, not a general one. So the finding on a new dialog is "it dismisses
differently from its siblings", never "import the shared Dialog", which does not exist.
2. **A second recipe for a concept that already has one.** Two ways to render the same
status, two ways to load the same resource, a new hook beside an existing hook doing that
job. The cost is that every later change has to be made in both places.
3. **Presentation and logic tangled in one component.** Fetching, polling, or business rules
inside a component that also owns layout, where a sibling in the same directory keeps them
apart. Say which half should move and where it goes.
4. **State that should be derived.** A `useState` paired with a `useEffect` that only
recomputes a value from props or other state: it can go out of sync, so compute it during
render instead.
5. **An effect doing an event handler's job.** Work belonging in the click, submit, or change
handler placed in a `useEffect` keyed on the value it just wrote. Those also fire on mount
and on unrelated re-renders.
6. **A redefined token or a one-off style.** A literal colour, radius, font size, or spacing
where a `var(--...)` token exists, or a new class where an existing one fits.
`packages/harness/CLAUDE.md` rule 6 is the standard: read tokens with `var()`, never
snapshot their values, because a local copy drifts the moment the design system moves.

**Do not flag**: naming, file placement, prop ordering, unmeasured memoisation, "consider
extracting" on a component nobody has had to change twice, a missing test for a purely
visual change, or any divergence from a design mock. Do not ask a PR to extract a shared
primitive that does not exist yet: introducing one is a design decision with its own
ticket, and demanding it in review is how an unrelated change gets blocked on somebody
else's refactor. Hygiene findings never outrank the
confidentiality and published-package findings above; a section that floods the PR with
nitpicks gets the whole review ignored, which is worse than not writing it.

## General review

Code quality, potential bugs, security concerns, test coverage. Use the repository's
Expand All @@ -280,7 +340,10 @@ jobs:
Length budget: 6,000 characters for a first review, 2,000 for a follow-up — a budget to
come in under, not a target. Do not add the `claude-review-sha` marker yourself.

claude_args: '--allowed-tools "Write,Bash(gh issue view:*),Bash(gh search:*),Bash(gh issue list:*),Bash(gh pr diff:*),Bash(gh pr view:*),Bash(gh pr list:*)"'
# Read/Glob/Grep are read-only on the PR checkout. The component-hygiene
# section requires naming the existing component or token a change
# bypasses, which is a claim about the repo, not about the diff.
claude_args: '--allowed-tools "Write,Read,Glob,Grep,Bash(gh issue view:*),Bash(gh search:*),Bash(gh issue list:*),Bash(gh pr diff:*),Bash(gh pr view:*),Bash(gh pr list:*)"'

- name: Post review comment
if: steps.pr.outputs.should_run == 'true'
Expand Down
72 changes: 72 additions & 0 deletions docs/plans/agent-studio-plan-first-agent-map/design.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
# Agent Studio unified Agent Map

Status: implemented by SAP-3148 through SAP-3151; SAP-3152 verifies and
reconciles the cutover.

## Product authority

Every Studio project session is one ordinary writable project agent. Its
trusted principal is `{ projectId, userId, sessionId }`, derived by the server.
Assignment, map-node, and focused-brief references are context, never
authorization. Every project session receives the same project-agent prompt,
Agent Map tools, build-plan tools, coding surface, and delegation tool subject
to normal project isolation and capability lifecycle.

The project owns one durable Agent Map and one current project build plan.
Sessions read and update that shared state through validated tools. A clear
implementation request proceeds directly. Agents update the map or plan only
when work changes architectural boundaries, ownership, contracts, resources,
connectors, artifacts, sequencing, or cross-agent flow. Internal code choices
remain local.

## Navigation

The project name selects the production Agent Map. That selection is a
deterministic read of durable state and never creates, resumes, focuses, or
prompts a session. Every session tab selects exactly one ordinary conversation
and its Canvas/Steps surface. A new project starts with one ordinary session
initially named `Plan Agents`; the name and first position grant no special
authority.

## Bootstrap and continuous maintenance

Project creation durably schedules one evidence-first bootstrap turn for the
first ordinary session when the map is meaningfully empty. Attempts, readiness,
preemption, retry, restart recovery, and delivery correlation are durable and
idempotent. User input remains usable and wins races without being discarded.
Opening the map does not trigger model work. After bootstrap, the common prompt
makes map maintenance a responsibility of every session.

## Versions, briefs, and delegation

Map, plan, and brief content use canonical digests and project-bound immutable
version references. Accepted changes append a version and atomically advance a
current pointer. Concurrent writes use exact expected versions; stale overlap
conflicts require reread/rebase. Restoration appends a new record carrying
`restoredFromVersionId`; history is never rewritten or rewound.

Focused briefs are deterministic, bounded, exact-source context overlays. They
focus a mission, scope, dependencies, contracts, deliverables, constraints, and
acceptance evidence without changing prompt or tools. Sessions without briefs
retain full capabilities and global context.

Any project agent may delegate writable work. The coordinator uses stable
project/parent/key bindings, durable spawn claims, exact session reuse,
readiness-gated kickoff delivery, acknowledgement, bounded retention, nested
delegation, and explicit stale-context recovery. Cleanup owns only sessions it
created; unrelated manual sessions are never adopted or mutated.

## Evidence boundary

Source and runtime evidence may verify or challenge project intent but never
silently becomes intent. The per-agent execution graph remains the authority for
internal steps and ordinary tool calls. The project map stays at architectural
altitude.

## Security and observability

Trusted scope never comes from model arguments. Capabilities are private,
project/session-scoped, rotated on resume, revoked on exit, and rejected across
projects. Telemetry records bounded lifecycle outcomes and identifiers only; it
must not contain prompts, plan prose, source text, paths, credentials, connector
payloads, or raw provider errors.
19 changes: 19 additions & 0 deletions docs/plans/agent-studio-plan-first-agent-map/journey-roadmap.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{
"schemaVersion": 1,
"authority": "SAP-3147",
"checkpoint": "SAP-3152",
"currentStack": [
{ "issue": "SAP-3148", "pr": 804, "head": "5d00c55925d1907670bed6e885384b25eb775a73", "outcome": "unified identity, bootstrap, and navigation" },
{ "issue": "SAP-3149", "pr": 806, "head": "90eb569eb6b90b917c49128b6a23c7215a0843d6", "outcome": "neutral immutable versions and universal plan authoring" },
{ "issue": "SAP-3150", "pr": 807, "head": "acb2dbae6a3e533e01a065c43fa4109bdd82ca14", "outcome": "role-neutral focused briefs" },
{ "issue": "SAP-3151", "pr": 808, "head": "ca747232e0b775b5be5c69c5427c778b3774dd4f", "outcome": "writable idempotent nested delegation", "review": "user-directed exception recorded in cutover ledger" },
{ "issue": "SAP-3152", "pr": null, "head": null, "outcome": "verification, documentation, and reconciliation" }
],
"dependencyOrder": ["SAP-3148", "SAP-3149", "SAP-3150", "SAP-3151", "SAP-3152"],
"historicalFoundations": ["E0", "E1", "E2"],
"laterWork": [
{ "epic": "E6", "directive": "consume shared neutral map, plan, brief, and session context" },
{ "epic": "E7", "directive": "reconcile evidence without silently changing intent" },
{ "epic": "E8", "directive": "adopt existing projects and remove obsolete authority without changing the per-agent graph" }
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
# Unified Agent Map journey interfaces

## Shared identity

```ts
type ProjectAgentSession = Readonly<{
projectId: StudioProjectId;
userId: UserId;
sessionId: SessionId;
}>;
```

The server derives this identity for creation, resume, bootstrap, manual
sessions, and delegated sessions. Focus references are carried separately.

## Navigation seam

- Project-name selection renders `AgentMapPane` and does not change the active
session ID.
- A session-tab selection activates that exact session and renders the ordinary
conversation plus Canvas/Steps.
- The tab key is the durable session ID; there is one visible tab per live ID.

## Map and plan seam

- `GraphContentDigest` identifies canonical semantic graph content.
- `AgentMapVersionRef` binds `projectId`, `versionId`, and `contentDigest`.
- `ProjectAgentActorRef` records trusted user/session attribution.
- `ProjectBuildPlanVersion` is immutable and exact-map-bound.
- `AgentBriefVersion` is immutable and exact map/plan-bound.
- Current reads and historical exact-version reads are distinct operations.
- Apply/rebase/restore append before atomically advancing a pointer.

All sessions discover `agent_map_read`, `agent_map_validate`,
`agent_map_propose`, `build_plan_read`, `build_plan_validate`,
`build_plan_apply`, `build_plan_rebase`, `build_plan_brief_refresh`, and
`project_subsession_delegate`.

## Focused-context seam

A focused projection is allowlisted, deterministic, source-verified, and size
bounded. Authored prose is delimited as untrusted data. The projection excludes
secrets, raw evidence, local paths, connector values, unrelated history, and
arbitrary instructions. It supplements the common project-agent prompt.

## Delegation seam

Delegation authority comes from the caller's private project capability. Inputs
contain a stable request key, stable delegation key, assignment, and optional
exact focused-context reference; they contain no trusted project/user/session
selector. Durable claims fence creation, spawning, kickoff, acknowledgement,
release, and restart recovery. Nested delegation uses the same interface and
capabilities. Manual sessions remain outside coordinator ownership.

## Future journey contracts

Later shared-context, reconciliation, and existing-project adoption work must
consume these neutral identity, version, brief, and session contracts. Evidence
remains diagnostic; no later issue may add an approval or mode boundary before
ordinary coding or delegation.
39 changes: 39 additions & 0 deletions docs/plans/agent-studio-plan-first-agent-map/rollout-rollback.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# Unified Agent Map rollout and recovery

## Release gate

Ship desktop beta first. Before a tag, record the exact main SHA, changeset
files, generated release PR, desktop package version, last known good tag, and
the intended `vX.Y.Z-beta.N` tag. Build and smoke the packaged AppImage, inspect
the packaged resources when runtime files changed, and walk the project-map,
ordinary-session, direct-build, and delegation journeys.

The npm path is changeset → merged version PR → publish. The desktop path is a
tag exactly matching `packages/harness-desktop/package.json`. Stable release is
allowed only after beta evidence and the update manifests are present.

## Rollback reality

There is no in-place downgrade for users who already installed a bad npm or
desktop version. Recovery is roll-forward:

1. identify and revert the faulty commit on a new branch;
2. add a new changeset and publish a strictly higher package version;
3. build and publish a strictly higher desktop tag;
4. verify installers, `latest*.yml`, and blockmaps remain available for the
last known good and new recovery releases;
5. use deprecation only as an installer warning, never as an unpublish plan.

Deleting a tag or release cannot downgrade installed desktop applications and
may strand the updater. `SAPIOM_UPDATE_CHANNEL` is a single-machine diagnostic,
not fleet rollback. Record an out-of-hours approver and drill the full
revert→changeset→version-PR→tag sequence before stable rollout.

## Product-state restoration

Product restoration is separate from binary rollback. A map or plan restore is
an ordinary expected-version write. It appends a new immutable version whose
content matches the selected historical version and whose
`restoredFromVersionId` names that source. The previous history remains
byte-for-byte unchanged, the current pointer advances atomically, and a stale
restore conflicts like any other concurrent write.
Loading
Loading