94ecb633a04231dc239df3b23f36604ba781e416
10
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
5c6175ad97 |
feat(placement): a record you only cite carries its status (#4154)
CI & Build / Python lint (push) Successful in 3s
CI & Build / Plugin hooks (push) Successful in 8s
CI & Build / integration (push) Successful in 50s
CI & Build / TypeScript typecheck (push) Successful in 52s
CI & Build / Python tests (push) Failing after 1m4s
CI & Build / Build & push image (push) Skipped
Step 1 made placement cheap for a task whose status CHANGES: create_task and update_task return where it sits, and the report is written from that. It did nothing for a task a reply merely cites. This milestone's own step-6 review reported "#4014 is the open step of milestone 409". #4014 had been done for four days; the open step was #4015. The id did not come from a read — it came from a retrieval hint, which carries an id, a kind and a title and says nothing about status, while list_milestones said "8 of 9" and would not say which one. The gap was there to be filled and the nearest-looking id filled it. Two surfaces, one principle: the status arrives with the id. 1. get_project_milestone_summaries gains next_step — the earliest open step, {id, title, status} or None — carried through _BRIEF_FIELDS to enter_project, get_project and list_milestones. One extra flat query for the whole batch, so #2384's fan-out does not come back. OPEN_STEP_STATUSES moves to services/milestones.py and placement.py imports it; both surfaces now answer "what is next" and must not drift on what counts as open. Both step queries take the same readable_notes_clause (rule 78), so a row cannot name a step its own progress numbers exclude. 2. _record_kind renders a task's status: [task (done)], [issue (todo)]. A finished step and an open one read identically before, which is exactly the line the misreport was taken from. Only tasks — is_task IS status-is-not-None on the model, so there is no fallback branch. reporting-back gains the practice, owned and registered in the guidance ownership table: a record you only mention is a record to read. The guards are structural and each fails on the regression it names: the query count is asserted rather than the payload shape, and the two surfaces' agreement is pinned on the rendered ORDER BY, since a mocked session hands back whatever order the test chose. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01821k5B3Ysecp9fNYs92Kuy |
||
|
|
b5df9d6dca |
feat(plugin): a reply's sections are chosen, not filled (#4153)
CI & Build / Plugin hooks (push) Successful in 13s
CI & Build / Python lint (push) Successful in 4s
CI & Build / TypeScript typecheck (push) Successful in 53s
CI & Build / integration (push) Successful in 49s
CI & Build / Python tests (push) Successful in 1m30s
CI & Build / Build & push image (push) Successful in 16s
Milestone 409 step 6 measured the scaffold on live sessions and found its
two halves disagreeing: adherence passed and the read test failed.
Completion replies carried every section the table asks for and were
still hard to read.
The cause was in the skill, not in compliance with it. It said to pick a
kind of reply "then fill its sections... keep them even when one is
short", which is an instruction to complete a form, and nothing anywhere
set a ceiling. A faithful reply and an unreadable one were the same
reply.
Four changes to the discipline around the scaffold. The categories and
their sections are untouched.
- Sections are what to consider including, not a form to complete. A
section answering a standing question ("does anything need me?") is
always answered, even with "nothing"; a section that explains earns its
place only when it changes what the operator does. Otherwise it belongs
in the record's log, where it is available and not in the way.
- Write the shortest reply that carries the answer, with named exceptions
so this cannot be read as "always be terse".
- "Needs you" takes BOTH tests: theirs to decide, AND work is waiting on
it. A question answerable by reading something or taking an available
measurement is work not yet done, not a request — settle it, say which
way you went, and leave them free to overrule.
- A decision already made gets acted on. Re-arguing a settled question
reads as contradicting yourself rather than as being careful, and costs
the operator the decision twice.
"Before sending" gains a second pass for what can go, since the existing
check asks what is MISSING, which a bloated reply passes.
Guards in tests/test_reply_discipline.py, three topics registered for
ownership. Every guard was falsified against the pre-change text before
committing (rule 167): all five fail on it and pass on the fix, and the
sixth deliberately passes both since it guards the scaffold against
collateral damage. No absence checks — the skill legitimately discusses
filling in order to warn against it, so asserting "fill" is absent would
false-alarm on the corrected text (snippet #3352).
Instance-agnostic per rule 115: the added text carries no record ids, no
software-specific terms and no verbatim quotes.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01821k5B3Ysecp9fNYs92Kuy
|
||
|
|
104c1d6f37 |
feat(plugin): a recognized retrieval miss has a route, and the record comes first (#4133)
CI & Build / Python lint (push) Successful in 3s
CI & Build / Plugin hooks (push) Successful in 9s
CI & Build / integration (push) Successful in 50s
CI & Build / TypeScript typecheck (push) Successful in 55s
CI & Build / Python tests (push) Successful in 1m34s
CI & Build / Build & push image (push) Successful in 43s
The tuning loop shipped in steps 4 and 6 and logged zero events in its lifetime. `tune_retrieval`, `retrieval_telemetry` and `retrieval_surfaces` appeared on no instruction surface at all — not the skills, not the hooks, not the MCP instructions — so the decision that "the model should be the thing handling it 9 times out of 10" could not begin to happen. What was missing was not an auditor but a route. `using-scribe` now carries it, ordered: read the refused records, fix the trigger, and only then consider the dial. The order is the content. A rule's `when_to_apply` IS the text its score is computed against, so a miss is evidence about that text first; rewording one trigger changes one rule's reach, while moving a floor changes what every record on the surface does and cannot tell a badly-worded trigger from a genuinely distant one. Measured, and the reason the order is asserted rather than suggested: rule 1 scored 0.6515 and ranked 5th for the moment it governed, behind three rules that restrained the same act. Every percentile said "lower the floor"; at 0.60 the arm delivered those three restraints and still not rule 1. Rewriting the trigger to lead with the symptom put it 1st at 0.7130. Also: the create path gets a precondition. A new record is itself a retrieval-affecting act, so before writing one, what_might_apply asks what already covers that moment — fifty candidates and no bar, because a bar is what lets the existing record hide. `_INSTRUCTIONS` gets one index line, not the route: 1,986 of 2,000 characters, since Claude Code cuts the rest mid-word (#2562). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01821k5B3Ysecp9fNYs92Kuy |
||
|
|
fb36599f2d |
docs(plugin): find the existing plan before making one, and file related work into it (#4080)
CI & Build / Python lint (push) Successful in 2s
CI & Build / Plugin hooks (push) Successful in 11s
CI & Build / integration (push) Successful in 57s
CI & Build / TypeScript typecheck (push) Successful in 1m15s
CI & Build / Python tests (push) Successful in 1m46s
CI & Build / Build & push image (push) Successful in 35s
Step 5 of milestone 415 "An existing plan is found before a new one is made". Sessions opened a second milestone beside the roadmap milestone that already covered the work, and filed related tasks loose, because no surface told them to look first. - writing-plans: a section on finding the plan that exists (enter_project's unplanned_milestones, search(content_type="milestone"), list_milestones); when an active milestone covers the work, add steps to it; a second milestone only for a separate arc; the gate's existing_milestone reply. - using-scribe: "when you plan" gains the same check and milestone_id on related tasks. - _INSTRUCTIONS PLAN line points at the milestone search (1,689 of 2,000). - test_guidance_ownership pins the topic on writing-plans. - Plugin version minted: 2026.09.15.1744. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01821k5B3Ysecp9fNYs92Kuy |
||
|
|
7f974d9749 |
feat(mcp): enter_project becomes a small primer: goal, recent work, open work, vocabulary (#4045)
CI & Build / Python lint (push) Successful in 3s
CI & Build / Plugin hooks (push) Successful in 9s
CI & Build / integration (push) Successful in 46s
CI & Build / TypeScript typecheck (push) Successful in 53s
CI & Build / Python tests (push) Successful in 1m44s
CI & Build / Build & push image (push) Successful in 23s
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 |
||
|
|
921565696c |
feat(409): an operator's own reply shapes reach the reply they are about (#4013)
CI & Build / Python lint (push) Successful in 3s
CI & Build / Plugin hooks (push) Successful in 11s
CI & Build / integration (push) Successful in 48s
CI & Build / TypeScript typecheck (push) Successful in 54s
CI & Build / Python tests (push) Successful in 1m24s
CI & Build / Build & push image (push) Successful in 23s
The reporting-back skill ships default shapes; an operator's adjustments to them are preference records. Prompt-time retrieval matches the operator's message, and a shape preference is about the reply, so those preferences were on file and never arrived. Operator's decision (logged on #4013): the server delivers them for a completion report, and the skill asks for every other kind. - Completion reports (option C): closing a task with update_task runs a kind-filtered preference search for the moment "writing the completion report after finishing a task" and returns matches as `reply_preferences` ({id, title, statement, kind}), with a sentence added to `report_back` naming the key. A preference says it is about completion reports through its own when_to_apply; no tag or column. Omitted when nothing matches, and the lookup fails open. - Telemetry: every call logs to retrieval_logs under `report_preference` (empty calls included; a search that never ran writes no row) and hits are recorded surfaced. The source is ranked, so it counts toward pull-through. The bar is the prompt arm's setting until step 6 reads this source's near misses. - Every other reply (option A): reporting-back gains "The operator's own shapes come first". Before a finding, decision, handoff or "where are we", search(content_type="rule") in the words of that moment and follow what comes back. Registered in the ownership guard with reporting-back as owner. - Loading reply shapes at session start (option B) was rejected: it would be a small copy of the preloading milestone 394 retired. Domain-neutral query (pinned); works on an install with no preferences. Plugin version minted. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> |
||
|
|
c440c49f5b |
test(410): an exactly-one-owner guard replaces the tests that required every surface to repeat itself (#4033)
CI & Build / Python lint (push) Successful in 3s
CI & Build / Plugin hooks (push) Successful in 12s
CI & Build / TypeScript typecheck (push) Successful in 54s
CI & Build / integration (push) Successful in 56s
CI & Build / Python tests (push) Successful in 1m30s
CI & Build / Build & push image (push) Successful in 15s
Step 6 of milestone 410 "One owner per piece of guidance". CI now keeps the shape decision #4027 set, so the next feature cannot quietly add a copy. tests/test_guidance_ownership.py, 33 topics, each with an owner, markers, a statement distinctive to the owner's full wording, and optional index markers: - test_every_topic_is_stated_by_its_owner: markers and statement on the owner - test_no_topic_is_stated_in_full_off_its_owner: the statement appears on no other session surface (index, adapter static text and commands, live context, other skills). Tool docstrings are not scanned; a contract may elaborate the reflex that calls it. - test_the_index_names_each_reflex_it_points_at: _INSTRUCTIONS keeps a one-line pointer for each session-start reflex - shared_with declares the one deliberate sharing: the note-check question lives in create_note and in using-scribe for two different moments, already pinned by test_verification_guidance_survives - test_the_ownership_guards_can_fail shows each guard turning red (rule 167) - the process topic now keys on get_process's "follow the returned body"; it had been passing on an unrelated "verbatim" in two other tools tests/test_instruction_surfaces_agree.py keeps only what ownership cannot enforce: the fold budget, rules-bind-names-preferences, and using-scribe's pointer to reporting-back. Retired: the every-session-start-surface ask and absence tests, the Systems and snippet owner pins (now registry topics), and the SessionStart-without-ask test (#2497's shape). The push has carried no rules since milestone 394, and requiring the ask beside every mention of it would force a copy. The module docstring records where each protection went. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> |
||
|
|
15621fa873 |
docs(410): a packaging contract, so a second client is a manifest and an adapter (#4032)
CI & Build / Python lint (push) Successful in 7s
CI & Build / Plugin hooks (push) Successful in 15s
CI & Build / TypeScript typecheck (push) Successful in 53s
CI & Build / integration (push) Successful in 56s
CI & Build / Python tests (push) Successful in 1m26s
CI & Build / Build & push image (push) Successful in 16s
Step 5 of milestone 410 "One owner per piece of guidance". The operator wants any attempt to package Scribe for another agent client to find the repo already in the right shape. plugin/PACKAGING.md (linked from the README) states: - what every client package shares: plugin/skills/ (verbatim), the /mcp endpoint and its in-band responses, the /api/plugin/* adapter endpoints (context, retrieve, prior-art, tool-rules, processes), and one fmcp_ key - what each client adds: a manifest; hooks limited to timing and transport; optional commands; adapter static text that never copies a skill or the index - the Claude Code adapter file by file, as the worked example - how Agent Plugins 1.0 clients (Codex, Cursor, Copilot/VS Code, Kiro, ChatGPT) and Gemini CLI would map, marked researched-not-tested (#4023) - four open questions for the second package: passing the key to the MCP server, whether two manifests can share one folder, hook parity, and where process skills go Hook audit: every hook prints only server-provided text, status or outage lines, the running version, or the compaction reload pointer. No guidance copies, so nothing moved. Guard: test_the_skills_reference_nothing_outside_their_folder fails on a relative path upward or a reference to plugin/, hooks/, commands/ or a manifest from inside a skill, with a companion test showing it can fail. Plugin version minted. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> |
||
|
|
0a29252f9b |
feat(410): the skills own the full reflexes, in words any client can read (#4029)
CI & Build / Python lint (push) Successful in 3s
CI & Build / Plugin hooks (push) Successful in 12s
CI & Build / integration (push) Successful in 53s
CI & Build / TypeScript typecheck (push) Successful in 55s
CI & Build / Python tests (push) Successful in 1m34s
CI & Build / Build & push image (push) Successful in 16s
Step 2 of milestone 410 "One owner per piece of guidance". Skills are the part of every client package shared verbatim (Agent Skills, decision #4027), so they state each reflex in full and name no particular client. using-scribe gains what only the static session context said: - a retrieved rule outranks a default habit; ask when no rule speaks to it - log on completing a task and on hitting a problem, not only successes - the systems_hint on an untagged record is the tagging question, answered at the moment of work Client-specific text leaves the skills, rewritten as the universal idea: - using-scribe: "keep one copy" no longer names CLAUDE.md, MEMORY.md, native auto-memory or autoMemoryEnabled; "this plugin" becomes Scribe - reusing-code / shape-accounting: Write/Edit and Bash become editor tools and shell edits; the prior-art "hook" becomes the prior-art hint; a plugin version number is dropped tests/test_guidance_ownership.py: - test_the_skills_name_no_particular_client fails on any Claude Code path, memory file, slash command, hook event or tool name in a skill, each marker commented with why it is client-specific; a companion test shows it can fail - three registry topics for what using-scribe now owns; the loss guard stays green Plugin version minted. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> |
||
|
|
f3036f0cd7 |
test(410): one guidance-topic registry, and a loss guard before anything moves (#4028)
CI & Build / Python lint (push) Successful in 3s
CI & Build / Plugin hooks (push) Successful in 13s
CI & Build / TypeScript typecheck (push) Successful in 56s
CI & Build / Python tests (push) Successful in 1m26s
CI & Build / Build & push image (push) Successful in 14s
CI & Build / integration (push) Successful in 53s
Step 1 of milestone 410 "One owner per piece of guidance". The later steps delete duplicate copies of agent guidance; this guard stops the last copy of a topic going with them. - tests/test_guidance_ownership.py holds the registry: 30 topics from the ownership map in decision #4027, each with its owner and marker phrases, and one definition of a delivered surface (_INSTRUCTIONS, tool docstrings, each skill, the static context, the adapter commands, the live session context). - The loss guard: every topic is stated in full, with all its markers together, on at least one delivered surface. A miss names the nearest partial match. - The owner column is recorded but not asserted yet; step 6 adds the exactly-one-owner guard once the moves are done. - test_the_loss_guard_can_fail proves split and absent markers are reported (rule 167). - The old DISPLACED_TOPICS list in test_instruction_surfaces_agree is folded in, so there is one list rather than two. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> |