Project context

The enrichment LLM sees a lot of per-feedback data — DOM, console, network, identity — but nothing about your product. Routes, terminology, current bugs, deliberate constraints. Without that, generated titles and summaries are generic ("the user wants the export to work") instead of grounded ("Export button on /billing/invoices spins forever — likely the same Stripe-webhook race in known_issues.md").

The fix: push a project brief once at install. The enrichment LLM loads it on every submission, prompt-cached so the cost is paid once per push.

What's in a brief

{
  sections: {
    name: string;                  // required
    tagline?: string;
    tech_stack?: string[];
    routes?: { path, purpose }[];  // up to 300
    glossary?: { term, definition }[]; // up to 200
    personas?: string;             // markdown
    known_issues?: string;         // markdown
    recent_changes?: string;       // markdown — usually auto-generated from git log
    conventions?: string;          // markdown
  },
  body?: string;                   // free-form markdown for anything else
  source: { agent, agent_version?, commit_sha? }
}

Soft budget: ~25K tokens rendered. Validated server-side; validate_project_context does a dry-run if you want to check first.

How to push it

Via your coding agent

Drop this in Claude Code / Cursor / Codex:

Use the earshot context skill to compile and push my project context.

The earshot-context skill reads:

  • README.md, package.json
  • Your route files (app/**/page.tsx, pages/**/*.tsx, etc.)
  • CLAUDE.md, CONTRIBUTING.md, docs/architecture*.md
  • Recent git log (last ~30 commits) for recent_changes
  • Schema files for the glossary
  • Any KNOWN_ISSUES.md

It assembles the brief, validates it, then calls set_project_context. Refresh anytime by rerunning the skill.

Via the MCP

set_project_context(sections, body?, source?, replace?)
get_project_context()
validate_project_context(sections, body?)
list_project_context_revisions()

See MCP.

How it's used

Inside summarizeFeedback, the rendered brief lives in its own Anthropic prompt-cache block above the per-feedback context:

system_prompt (cached)
project_brief (cached)
per_feedback_context
user_input

The brief is identical across every submission for the project, so the cache hit rate is high and the brief is effectively free past the first call.

The system prompt instructs the model to prefer host terminology from the glossary. "Sign in button in the header" beats "the login button"; "Plan v2 page" beats "settings page".

Don't push secrets

The brief is a database column that an LLM reads on every feedback submission. The earshot-context skill's hard rules:

  • Never read or forward .env values without explicit user permission per value.
  • Strip API keys, OAuth client secrets, JWTs, customer PII before pushing.
  • Don't log secrets to the chat.
  • Don't write secrets into version-controlled files.

source.agent is required so the dashboard's Project Context page can attribute pushes ("pushed by claude-code @ a5624bb").

When to refresh

  • After a substantial refactor or new feature ship.
  • After a release that changes terminology (renamed pages, new product surface).
  • If the dashboard shows the brief is older than ~30 days.
  • If feedback quality drops (lots of "the agent asked for context it should have already known" comments).