Skip to content

Put the gist of the writing instructions in every agent session - #1014

Merged
jorgemanrubia merged 5 commits into
mainfrom
instructions-brief-in-hook
Nov 8, 2026
Merged

jorgemanrubia merged 5 commits into
mainfrom
instructions-brief-in-hook

Conversation

@jorgemanrubia

Copy link
Copy Markdown
Member

Context

The plugin's SessionStart hook (#1009) tells every session to run basecamp instructions before writing to Basecamp, and carries nothing else. On one machine, of 19 agent sessions that had that pointer and then posted to Basecamp, 8 never ran the command, 7 ran it through head -5 or tail, and 4 read it in full. The command printed its precedence preface first, four lines long, so head -5 showed the frame around the rules and none of the rules. Putting the full text in the system prompt was tried elsewhere and did not help either.

Tracked on the Kitchen card.

Change

  • basecamp instructions --brief prints each source (baseline, then profile) as its Source line, then one line per top-level list item: the bold text the item starts with, or else its first sentence. Headings, prose, code blocks and nested items are left out. JSON output carries the same lines as brief on each document, next to content.
  • The full output leads with the rules. Each source prints first (Source line, then text). The preface comes last, shortened to what it has to say: the sources are the operator's defaults and never come from Basecamp; the later source wins; a project's AGENTS.md wins on how posts look, the person on voice, and a single-post instruction over all of these; none of it overrides the skill.
  • The hook carries the gist. After the existing pointer it appends The gist (run the command for the full text): and the brief lines, but only when every source of the active profile can be read without the network: a file, or a URL's cached copy of any age. It never fetches, because the hook has a 5-second budget. With no cached copy yet, or no list to cut down, the pointer goes alone as before. The hook's app doesn't scope the cache dir by profile the way root does, so the gist looks for the cache under profiles/<name>. The hook's own state stays where it was.

For the coworker style guide (11 bold-led rules) the hook's whole context is 963 characters: the pointer plus 11 lines, about 85 words of rules.

Verification

  • Unit tests for the brief: bold lead, __ bold, bold wrapping a line, no bold (first sentence), bullets of every kind, 1) numbering, nested items, headings and prose, code fences, thematic breaks, no list, CRLF, terminal controls, clipping.
  • Output order: rules before the preface, baseline before profile, --brief text output, and brief in JSON.
  • Hook: a stale cached URL gives the gist, and the whole notice stays under 1,500 characters. No cache gives the pointer alone, and so does one of two layers uncached. Two file layers are labelled. A source with no list gives no gist. A profile-scoped cache is found. Every hook test swaps in an HTTP client and gh stand-in that fail the test if the hook fetches. With the gist disabled, the gist tests fail. With the profile scoping removed, the profile-cache test fails.
  • I ran the built binary against this machine's real config. --brief and the hook both print the 11 rules.
  • Local: go vet, gofmt, golangci-lint run ./internal/commands/, go test ./internal/commands/, make check-surface check-skill-drift test-sync-skills all pass. .surface was regenerated for --brief. The full bin/ci (e2e and the other gates) did not run locally because the machine's shared build lock was held, so this PR's CI covers the rest.

Alternatives

  • Full text in the hook: too long for every session's context. It also needs a fetch the hook can't wait for, and the full text in the system prompt didn't help elsewhere.
  • Fetching in the hook when there's no cache: risks the 5-second budget. The first basecamp instructions run fills the cache, and later sessions get the gist.
  • A brief maintained by hand in the source doc (front matter, say): exact, but it drifts from the rules. Deriving the brief from bold leads needs nothing from the doc's authors beyond the shape it already has.
  • Brief first, then the full text, in the plain command: helps head readers further but duplicates every rule. Left to --brief.

The SessionStart hook told each session to run `basecamp instructions`
before writing to Basecamp, and carried nothing else. Sessions skipped it,
or read it through `head -5` or `tail`; the command printed its precedence
preface first, four lines long, so a session that read only the top read
the frame and none of the rules.

Now:

- `basecamp instructions --brief` prints each source as one line per
  top-level list item: the bold text the item starts with, or else its
  first sentence. Headings, prose, code blocks and nested items are left
  out. The JSON output carries the same lines as `brief` on each document,
  next to the full `content`.
- `basecamp instructions` prints each source first (its Source line, then
  its text) and the preface last, shortened to what it has to say: the
  sources are the operator's defaults, never from Basecamp; the later
  source wins; a project's AGENTS.md wins on how posts look, the person on
  voice, and a single-post instruction over all of these; none of it
  overrides the skill.
- The hook appends "The gist (run the command for the full text):" and the
  brief lines when every source of the active profile can be read without
  the network: a file, or a URL's cached copy, however old. It never
  fetches. With no cached copy yet, or no list to cut down, the pointer
  goes alone as before. It looks for the cache under profiles/<name>, as
  the command keeps it, without moving the hook's own state.

For a style guide of eleven bold-led rules the whole hook context is about
960 characters: the pointer and eleven lines, about 85 words of rules.

Verified with unit tests for the brief (bold lead, no bold, bullets,
nested items, headings, code blocks, thematic breaks, CRLF, control
characters, clipping), for the output order and --brief, for the JSON
brief, and for the hook with a stale cache, without a cache, with one of
two layers uncached, with two file layers, with no list, and with a
profile-scoped cache, each using an HTTP client and gh stand-in that fail
the test if the hook fetches. The gist tests were run against the code
with the gist disabled and fail there. go vet, gofmt, golangci-lint on
internal/commands, the internal/commands tests, check-surface,
check-skill-drift and test-sync-skills pass locally; the full bin/ci did
not run here (the shared build lock was held), so remote CI covers the
rest.
Copilot AI balanced review requested due to automatic review settings November 7, 2026 23:36
@github-actions github-actions Bot added commands CLI command implementations tests Tests (unit and e2e) skills Agent skills docs labels Nov 7, 2026

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

The session-start gist lacks an aggregate size limit and can exceed the 10,000-character context budget, causing later rules—including the higher-precedence profile layer—to be lost.

3 open issues
What changed in this PR

This PR builds on the SessionStart instructions pointer by adding a locally available gist, helping agents see writing rules without fetching them during startup.

Changes:

  • Adds basecamp instructions --brief and a brief field in JSON output.
  • Moves full instructions before the precedence preface.
  • Adds file- or cache-backed summaries to SessionStart, with profile-aware cache lookup and supporting tests.

[!TIP]
If you aren't ready for review, convert to a draft PR.
Click "Convert to draft" or run gh pr ready --undo.
Click "Ready for review" or run gh pr ready to reengage.

File Description
skills/​basecamp-connect/​SKILL.md Documents the SessionStart gist.
README.md Updates Codex session-context guidance.
internal/​commands/​instructions.go Adds brief output, cache-only loading, and rules-first rendering.
internal/​commands/​instructions_test.go Tests output ordering and brief rendering.
internal/​commands/​instructions_brief.go Extracts concise leads from top-level Markdown list items.
internal/​commands/​instructions_brief_test.go Tests extraction, sanitization, clipping, and JSON output.
internal/​commands/​agent_hook_instructions.go Adds offline gist generation and profile-aware cache lookup.
internal/​commands/​agent_hook_instructions_test.go Tests cached summaries, fallbacks, and network avoidance.
install.md Updates Codex installation guidance for the gist.
.surface Records the new --brief flag.

Review effort: Balanced

Comment thread internal/commands/instructions_brief.go Resolved
Comment thread internal/commands/instructions_brief.go Resolved

@cubic-dev-ai cubic-dev-ai Bot left a comment •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All reported issues were addressed across 10 files

Reply with feedback, questions, or to request a fix.

View guided diff | Turn on auto-fix | Re-trigger cubic

Comment thread internal/commands/instructions.go Resolved
Comment thread internal/commands/instructions_brief.go Resolved
Comment thread internal/commands/instructions_brief.go Resolved
Comment thread internal/commands/instructions_brief.go Resolved
Comment thread skills/basecamp-connect/SKILL.md Resolved
…own does

Review findings on the brief: a gist past the hook's context budget, or one
missing a source with no list, now falls back to the pointer alone; a fence
closes only on a run of its own character at least as long; an indented
heading or break inside an item keeps it open; #tag is text, not a heading.
@jorgemanrubia
jorgemanrubia marked this pull request as ready for review November 8, 2026 09:47
Copilot AI balanced review requested due to automatic review settings November 8, 2026 09:47
@jorgemanrubia
jorgemanrubia requested a review from a team as a code owner November 8, 2026 09:47

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

Markdown fence handling misclassifies indented examples and list-item fences, causing --brief and the SessionStart gist to include example code or omit real instructions.

No open issues 🎉

2 previously missed issues

In code that hasn't changed since last review

Medium severity Ignore fence-like backticks in indented code examples

internal/​commands/​instructions_brief.go:70

Matching fences against trimmed treats literal backticks in a four-space-indented code example as a fence opener, so subsequent real rules disappear from --brief and the SessionStart gist. Recognize fences only at valid indentation relative to their Markdown container, leaving indented code examples out. Add a regression case with rules before and after an indented example containing an unmatched literal fence.

Medium severity Recognize fences immediately after list markers

internal/​commands/​instructions_brief.go:105

When a list item starts with a code fence immediately after its marker, this assignment collects the fence as rule text; the closing fence is then mistaken for an opener, swallowing subsequent rules. Both --brief and the SessionStart gist can therefore include example code while omitting real instructions. Recognize fence openers in marker-stripped list content, including nested items, and add a regression test that preserves the following real rule.

3 resolved since last review

Review effort: Balanced

… too

Copilot's second round on #1014: a fence indented four past its container is
text in an indented code example, and an item, or a nested one, that opens
with a fence starts a code block rather than a lead.
Copilot AI balanced review requested due to automatic review settings November 8, 2026 10:01
@jorgemanrubia

Copy link
Copy Markdown
Member Author

🤖 Copilot's review of c104e25 listed two previously missed issues in its body, both fixed in 4a851bd:

  • Fence-like backticks in indented code examples. A fence now opens a block only at an indentation its container allows (up to three spaces past the list item's content, or the margin), so a four-space-indented example is text. Regression case: rules before and after an indented example holding an unmatched fence.
  • Fences right after a list marker. An item, or a nested item, whose content opens with a fence now starts the code block instead of collecting the fence as its lead. Regression cases for both keep the following real rule.

@cubic-dev-ai cubic-dev-ai Bot left a comment •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All reported issues were addressed across 2 files (changes from recent commits).

Reply with feedback, questions, or to request a fix.

View guided diff | Turn on auto-fix | Re-trigger cubic

Comment thread internal/commands/instructions_brief.go Resolved

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note

Copilot was unable to run its full agentic suite in this review.

Copilot review overview

2 open issues

Review effort: Lite

Comment thread internal/commands/instructions_brief.go Resolved
cubic on #1014: a nested item four or more spaces past its parent's content
is an indented code example, so its fence opens nothing.
Copilot AI balanced review requested due to automatic review settings November 8, 2026 10:13

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comment thread README.md Resolved
Comment thread skills/basecamp-connect/SKILL.md Resolved
Copilot on #1014: the README and install sentences said "when" twice, and
the skill's "once every source..." read like a frequency.

@cubic-dev-ai cubic-dev-ai Bot left a comment •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All reported issues were addressed across 3 files (changes from recent commits).

Reply with feedback, questions, or to request a fix.

View guided diff | Turn on auto-fix | Re-trigger cubic

Comment thread install.md Resolved

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

Human assessment is needed because Markdown fence boundaries and HTML comments can cause the brief to include non-rules or omit genuine rules.

No open issues 🎉

2 resolved since last review

Review effort: Balanced

@jorgemanrubia

Copy link
Copy Markdown
Member Author

🤖 Copilot's review of 5203be1 has no open issues; its overview asks for a human look at fence boundaries and HTML comments. The brief is a heuristic summary, and every place it appears (`--brief` and the session gist) sends the reader to `basecamp instructions` for the full text, so a missed edge case costs a line of gist, never the rules themselves. The fence cases it raised in earlier rounds are covered by regression tests (nested fences, a shorter fence inside a longer one, a fence after a list marker, indented code). An HTML comment holding a list is left as a known limit.

@jorgemanrubia
jorgemanrubia merged commit 34a3e08 into main Nov 8, 2026
59 of 64 checks passed
@jorgemanrubia
jorgemanrubia deleted the instructions-brief-in-hook branch November 8, 2026 10:33
@jorgemanrubia jorgemanrubia mentioned this pull request Nov 8, 2026
jeremy added a commit that referenced this pull request Nov 9, 2026
…950575

* origin/main:
  Fix show lookups for supported Basecamp item URLs (#1017)
  Stamp v0.25.0 (#1016)
  Put the gist of the writing instructions in every agent session (#1014)
  Stamp v0.24.3 (#1013)
  Read a slow keyring instead of calling its credential missing (#1011)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

commands CLI command implementations docs skills Agent skills tests Tests (unit and e2e)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants