enter_project(2) returned 221,862 characters. That's past what Claude Code accepts as a tool result, so the session handshake arrived as a file. This PR reshapes it into a primer, about 7k characters for project 2. The shape was decided category by category with the operator (#4045 "enter_project's payload is too big for the client").
What the handshake carries now
Key
Before
After
project
whole record
id, title, status, full goal
milestone_summary
every milestone with its full plan
the 5 most recently touched (step updates count), no plans, plus a count of the rest
open_tasks
10 by last edit
10 most recently touched (work-logs count), each naming its milestone
recent_notes
5 titles
removed (retrieval covers it)
systems
id, name, charter line
id, name
design_system
~9k of guidance
summary + guidance_call; get_design_system now returns resolved_guidance
rules
full text and bookkeeping
project rule ids and titles, subscribed rulebooks
pattern_coverage, inception, systems_bootstrap
—
unchanged
Other changes
Milestone summaries: gain last_touched_at. get_project and list_milestones list every milestone, without plans.
list_notes: gains sort="touched".
rules_payload: gains a brief mode, used only by enter_project.
Plugin (version 2026.09.15.0204): the using-scribe skill wording, the session-start design pointer and the compaction notice now match the new shape.
REST project summary: only gains last_touched_at; the web UI is unaffected.
Verification
CI run 522 on 7f974d9 passed every job. That includes a size limit on the handshake for a large synthetic project, and a real-Postgres test that work-logs and step updates count as "touched". The live payload size will be measured after deploy.
`enter_project(2)` returned 221,862 characters. That's past what Claude Code accepts as a tool result, so the session handshake arrived as a file. This PR reshapes it into a primer, about 7k characters for project 2. The shape was decided category by category with the operator (#4045 "enter_project's payload is too big for the client").
## What the handshake carries now
| Key | Before | After |
|---|---|---|
| project | whole record | id, title, status, full goal |
| milestone_summary | every milestone with its full plan | the 5 most recently touched (step updates count), no plans, plus a count of the rest |
| open_tasks | 10 by last edit | 10 most recently touched (work-logs count), each naming its milestone |
| recent_notes | 5 titles | removed (retrieval covers it) |
| systems | id, name, charter line | id, name |
| design_system | ~9k of guidance | summary + `guidance_call`; `get_design_system` now returns `resolved_guidance` |
| rules | full text and bookkeeping | project rule ids and titles, subscribed rulebooks |
| pattern_coverage, inception, systems_bootstrap | — | unchanged |
## Other changes
- **Milestone summaries:** gain `last_touched_at`. `get_project` and `list_milestones` list every milestone, without plans.
- **`list_notes`:** gains `sort="touched"`.
- **`rules_payload`:** gains a brief mode, used only by `enter_project`.
- **Plugin (version `2026.09.15.0204`):** the using-scribe skill wording, the session-start design pointer and the compaction notice now match the new shape.
- **REST project summary:** only gains `last_touched_at`; the web UI is unaffected.
## Verification
CI run 522 on `7f974d9` passed every job. That includes a size limit on the handshake for a large synthetic project, and a real-Postgres test that work-logs and step updates count as "touched". The live payload size will be measured after deploy.
Commits: `9b2de35`, `7f974d9`.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
https://claude.ai/code/session_01821k5B3Ysecp9fNYs92Kuy
enter_project returned every milestone's full plan body. On a project with 39
milestones the handshake came to ~222k characters, 168k of them bodies (110k
from done milestones). That is past what an MCP client accepts as a tool
result, so the call meant to orient a session arrived as a file to page
through. It grows with a project's history, so any long-lived project on any
install gets there.
- brief_milestone_summary (services/milestones.py) trims summary rows to the
listing fields: id, title, description, status, order_index and progress.
The plan is get_milestone's job. user_id, project_id and timestamps repeat
what the caller knows.
- enter_project and get_project share one block: every open milestone plus
the 5 most recently updated done ones, in order. milestone_summary_omitted
is attached only when older done ones were left out, and names
list_milestones and get_milestone.
- list_milestones lists every milestone, done included, without bodies. It is
the call the omitted line points to, and it had the same size problem.
- The REST project summary is unchanged; the web UI reads it.
Tests: trimming, the done cap and its order, the omitted key present and
absent, get_project and list_milestones, and a size ceiling on enter_project's
milestone block for a 200-milestone history.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01821k5B3Ysecp9fNYs92Kuy
The handshake carried the whole project record, every milestone's plan, full
rule text, the notes most recently edited and ~9k of design guidance. For
project 2 that was ~222k characters, past what an MCP client accepts as a tool
result. Each category was walked through with the operator and sized to what a
session needs on arrival; each names the call that has the rest.
- project: id, title, status and the full goal (session start's "full goal"
pointer still lands here). get_project keeps the whole record.
- milestone_summary: the 5 most recently touched milestones, any status, most
recent first, without plans. Summaries gain last_touched_at: the later of
the milestone's own edit and its newest step update, from the query that
already counts steps. milestone_summary_omitted counts the rest and points
to list_milestones. get_project and list_milestones list every milestone,
also without plans.
- open_tasks: the 10 most recently touched open tasks, with or without a
milestone, each naming its milestone. list_notes gains sort="touched"
(the later of updated_at and the newest work-log), because a log doesn't
bump updated_at.
- recent_notes: dropped. Retrieval surfaces notes by relevance, and
get_recent covers recency.
- systems: id and name.
- design_system: summary plus guidance_call. get_design_system gains
resolved_guidance, the chain-merged prose; its own guidance field is only
the departures, so session start's old pointer to it led to a fragment.
The session start pointer and using-scribe's "Building UI" section now
name resolved_guidance.
- rules: rules_payload(brief=True) gives project_rules as id and title plus
subscribed_rulebooks, and records only what it shows. Retrieval delivers
rules in full and ignores subscriptions (#4052). Other callers unchanged.
- pattern_coverage, inception and systems_bootstrap: unchanged.
Clients: the plugin's using-scribe skill, the compaction notice and session
start are updated here; the REST project summary only gains last_touched_at.
Plugin version minted.
Tests: a size ceiling on the handshake for a large project; milestone and
task selection and naming; brief rules; resolved_guidance; the session
start pointer; and a real-Postgres test that a work-log touches its task and
a step update touches its milestone.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01821k5B3Ysecp9fNYs92Kuy
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
enter_project(2)returned 221,862 characters. That's past what Claude Code accepts as a tool result, so the session handshake arrived as a file. This PR reshapes it into a primer, about 7k characters for project 2. The shape was decided category by category with the operator (#4045 "enter_project's payload is too big for the client").What the handshake carries now
guidance_call;get_design_systemnow returnsresolved_guidanceOther changes
last_touched_at.get_projectandlist_milestoneslist every milestone, without plans.list_notes: gainssort="touched".rules_payload: gains a brief mode, used only byenter_project.2026.09.15.0204): the using-scribe skill wording, the session-start design pointer and the compaction notice now match the new shape.last_touched_at; the web UI is unaffected.Verification
CI run 522 on
7f974d9passed every job. That includes a size limit on the handshake for a large synthetic project, and a real-Postgres test that work-logs and step updates count as "touched". The live payload size will be measured after deploy.Commits:
9b2de35,7f974d9.🤖 Generated with Claude Code
https://claude.ai/code/session_01821k5B3Ysecp9fNYs92Kuy