primr
AGENTS.md3 starsChanged 24 days agoApache-2.0View on GitHub
You are working on the primr codebase. This file is the development contract and context map: read it before writing code. It is the single canonical guide for any contributor (human or agent). Tools that read the agents.md format load it natively; Claude Code loads it through the one-line CLAUDE.md import (@AGENTS.md). Keep agent guidance here, not in a second file, and keep tool settings (permissions, hooks) in each tool's own configuration rather than in prose. Operating primr is a…
- Reads credentials
1 other project uses a version of this.
Adopted by
Most recently taken up by
- pueo-labs/primrword for word, first seen Nov 1, 2026
Other versions1 project uses a version of this.
Word for word · 1
- pueo-labs/primr★ 3100% same
Edited · 0
None found.
Wrote their own version · 0
None found.
How matches are found. Word for word: the exact same text. Edited: shares passages with this file (“99% same” means 99% of its five-word phrases also appear here; 10% or more counts). Their own version: similar meaning, or, weakest, the same name. We can’t tell which project had it first. Projects are counted among the 200 most-starred candidates, and mentions are links to the repository we found, up to 50 per site, so both counts are a floor.
Where files are headingNew AGENTS.md files have more rules about keeping secrets out of the code, and fewer about code style.
Of the AGENTS.md files we read, the 31,542 first seen in the last six months, against the older ones: the kind of rule that gained most share, and the kind that lost most. About files like this in general, not this one, and an estimate, since a kind is a pattern in the words.
In this repository8 other files it gives its agents.
- CLAUDE.mdCLAUDE.md
- primr-zeroSkill
- primrSkill
- primr-zeroSkill
- company-researchSkill
- hypothesis-trackingSkill
- qa-iterationSkill
- scrape-strategySkill
The file
Show its rules and text
We split this AGENTS.md into the rules it gives an agent
19 rules. About 1 is common, 8 are distinctive, and 10 are very specific to this project.
≈1
Common · estimate
Many files like this have a rule of this kind.
≈8
Distinctive · estimate
This author's own choices. Worth a look.
10
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Distinctive: line 46
Put code in the package that owns it (see Architecture Pointers).
- Distinctive: line 48
Before opening a PR, run the Verification Commands and re-read the Negative Constraints.
- Very specific: line 57
Start with the README, product contract, docs/NEXT_STEPS.md, and the relevant roadmap/design sections.
- Very specific: line 65
Use the package map and recompute the AST import graph in tests/test_architecture.py when changing ownership or dependencies.
- Distinctive: line 81
Use autonomy according to consequence and reversibility: research, inspection, AST analysis, local reversible edits, unit tests, and …
- Distinctive: line 93
Keep planned, implemented, tested, shipped, deployed, and measured behavior distinct.
- Distinctive: line 112
Use the smallest boundary that satisfies the requirement:
- Distinctive: line 121
Do not add a language for architectural symmetry, popularity, or a microbenchmark alone.
- Very specific: line 192
NEVER trust training memory for "now.": Verify the current library version, API signature, and model ID (against uv.lock / config/models.py …
- Very specific: line 197
NEVER bypass the SSRF guard: Every outbound URL goes through utils.security.is_safe_url (validated post-redirect).
- Common: line 200
No secrets in code, logs, or fixtures.
- Very specific: line 214
Keep dependencies justified: never add an unimported or dead dependency to pyproject.toml.
- Distinctive: line 217
Keep writing professional: no emojis, em dashes, or en dashes in new documentation, comments, generated text, commits, PRs, or delegated …
- Very specific: line 222
Use the existing environment with --no-sync during verification to avoid implicit environment changes.
- Very specific: line 287
Update the released baseline in docs/NEXT_STEPS.md and the OpenClaw image version label.
- Distinctive: line 299
Check first: Before new work, run git fetch --prune and review git worktree list, local and remote branches, and open PRs.
- Very specific: line 304
Checkpoint and hand off: Commit and push at meaningful checkpoints.
- Very specific: line 305
Before stopping, leave a short handoff (PR description, commit message, or .agent/<task>/) stating what is done and what is next.
- Very specific: line 312
Remove only with evidence: Remove a worktree or branch only once its work is merged, contained in main, or pushed.
≈ “Common” is an estimate: at least 1 in 5 of the 40,246 AGENTS.md files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
AGENTS.md - the contract for building primr
You are working on the primr codebase. This file is the development
contract and context map: read it before writing code. It is the single
canonical guide for any contributor (human or agent). Tools that read the
agents.md format load it natively; Claude Code loads it
through the one-line CLAUDE.md import (@AGENTS.md). Keep agent guidance
here, not in a second file, and keep tool settings (permissions, hooks) in
each tool's own configuration rather than in prose.
Operating primr is a different guide. To use the primr CLI or MCP for research, read
clients/primr-operator.md, the operator guide that users copy into their own workspace asAGENTS.md. This file is about changing primr's source.
The bar: code any human or AI could admire - tidy, consistent, secure, well-tested. We are not making slopware. The rules below exist because AI-assisted code reliably regresses on exactly these axes (duplication, inconsistent patterns, stale APIs, silent insecurity) unless held to a contract.
Quick Start
primr turns a company name and website into sourced, long-form strategic
reports. It is a CLI-first, local-first Python package (src/ layout), an LLM
API client + adaptive scraper + MCP/A2A agent - it trains and serves no
models. To work on it:
The enduring product boundary is the
Company Analyst Product Contract:
the bare company-and-website invocation must produce exceptional researched,
long-form Strategic Overview and YAML-defined strategy artifacts as reliable
Word and Markdown files. Architecture, routing, ledgers, memory, and agent
surfaces are supporting capabilities, not replacement products.
Primr researches and ideates. It writes a deep Strategic Overview from site, hiring, news, recon, and industry research, then an AI Strategy and an optional skill pack that ideate from what it learned. Facts are cited where sources exist; strategy is informed reasoning because companies rarely publish it. Never frame report quality as fact verification. The hard floors (citations resolve, artifacts render, spend is gated) stay.
- Set up the dev env (
uv sync --locked --all-extras, thenuv run playwright install chromium) - seedocs/CONTRIBUTING.md. - Put code in the package that owns it (see Architecture Pointers). Use the existing seam rather than inventing a second way to do the same thing.
- Before opening a PR, run the Verification Commands and re-read the Negative Constraints. New code ships with tests; the coverage ratchet only rises.
Three rules in one breath: one way to do each thing; no new giant files; verify current APIs (never trust training memory). Everything below expands these.
Working loop and evidence
Start with the README, product contract, docs/NEXT_STEPS.md, and the relevant
roadmap/design sections. Check the working tree, recent changes, owning source,
callers, tests, pyproject.toml, uv.lock, and affected CI jobs before editing.
Source, configuration, tests, and release history outrank stale prose. Keep one
bounded objective and explicit acceptance criteria; do not reopen the stack or
expand into an unrelated cleanup. Ask about consequential product ambiguity,
not routine reversible implementation choices.
Use the package map and recompute the AST import graph in
tests/test_architecture.py when changing ownership or dependencies. Inspect
the actual symbols and callers; cached indexes and old audit counts can be
stale. Verify version-sensitive decisions against current primary sources,
distinguishing the locked baseline, stable upstream releases, and previews.
Record durable conclusions in the owning design doc, not this file.
Implement through the existing seam, run focused checks, inspect failures, fix
their cause, then run the broader gate and review the diff. When the same class
of issue occurs repeatedly, fix the system rather than only the local instance:
improve the shared abstraction, types, schemas, or tests so the error class
cannot recur. Do not pass by weakening types, schemas, assertions, coverage,
or security controls. The mypy baseline enforces check_untyped_defs = True
globally; mypy.ini owns its growing strict allowlist; new boundaries need
precise signatures and should join the allowlist where practical.
Use autonomy according to consequence and reversibility: research, inspection, AST analysis, local reversible edits, unit tests, and isolated worktree branches proceed with high autonomy. Mutating production systems, spending budget, publishing releases, or deleting data require explicit user approval.
Match evidence to the claim: MCP changes need real transport tests; portable plugins need installed-layout and persistent-state checks; generated artifacts need generator and package checks; report changes need rendered artifacts and source-grounded evaluation. Structural tests cannot establish semantic quality, and judge agreement needs independent correctness checks. Seek independent review for security or lifecycle changes after self-review.
Keep planned, implemented, tested, shipped, deployed, and measured behavior
distinct. Record exact verification and remaining limits; baseline CI does not
prove an unpushed patch. Treat every completed task as an update to project
state, not merely a patch of code: update tests, documentation, architecture
records, and docs/CHANGELOG.md under [Unreleased] before calling work
complete. Use the existing gitignored .agent/<task>/ for scratch research,
logs, indexes, and a resumable handoff with scope, decisions, changed paths,
checks, and blockers. Never store secrets there. Durable knowledge belongs in
source, tests, or owning docs.
Language and runtime choices
Primr is Python-first, not Python-only. Python owns research orchestration, provider integration, scraping policy, report generation, and the public package because ecosystem leverage and iteration speed dominate there. A different language or runtime is introduced only at a narrow, versioned seam after an optimized Python baseline and production-shaped profile show a material end-to-end benefit.
Use the smallest boundary that satisfies the requirement:
| Requirement | Preferred boundary |
| Cancellation, crash containment, resource limits | Supervised Python child process or one-job container |
| Deterministic CPU or memory hotspot | Optional Rust accelerator after differential and packaging gates |
| Independently scaled multi-user admission | Service boundary; Go only after measured control-plane load |
| Local model execution | External OpenAI-compatible server; no embedded runtime without a measured kernel |
Do not add a language for architectural symmetry, popularity, or a
microbenchmark alone. A proposal must include the bounded capability, current
baseline, target, production-shaped corpus, correctness oracle, supported
platform artifacts, observability and failure semantics, fallback, rollback,
security review, and maintenance cost. Base Primr must remain installable and
functional without a native compiler. The binding decision record and current
adoption gates live in
docs/design/runtime-language-boundaries.md.
Architecture Pointers
src/ layout, one package per concern. config/ is close to a leaf (avoid
new core/ai/data imports). Design docs live in
docs/design/; the full standards are in
ROADMAP → Engineering Standards.
<details>
<summary>Package map - where things live</summary>core/- pipeline orchestration, CLI, research agent, strategyai/- LLM clients, providers, routing, deep researchdata/- scraping engine (data/scraping/), hiring signals, fallback sourcespipeline/- recovery policy, retries, failover, and model circuit breakersprompts/- YAML prompt composition, shared rules, and strategy registryoutput/- report/strategy rendering (MD/TXT/DOCX), validationqa/- report analysis, calibration, scoringagentic/- hypothesis tracking, hooks, subagents, orchestratorskill_pack/- skill-pack planning/authoring/validationconfig/- settings, env, model registry, validation (keep near-leaf)utils/- shared seams (below); not a dumping groundmcp_server/,a2a/,api/- agent / HTTP surfaces
</details>Use the one seam - don't invent a sixth way
The fastest way to rot a codebase is N ways to do one thing. Before reaching for a library or pattern, use the existing seam.
<details>
<summary>Seam table - use these, not the alternatives</summary>| Need | Use | Not |
| Run async from sync | utils.async_utils.run_sync | bare asyncio.run / get_event_loop |
| Console output | utils.console.get_console() | print( in library code |
| Logging | utils.logging_config.get_logger(__name__) | logging.getLogger / print |
| Config / settings | config/ (settings, env, models) | ad-hoc os.environ reads |
| JSON | stdlib json | orjson / ujson / simplejson |
| Atomic file write | utils.atomic_io | raw open(...,'w') for state files |
| Model IDs / pricing | config/models.py registry | hardcoded model strings |
| Outbound HTTP | the scraping-tier clients / data.http_client | a new HTTP client |
| MCP HTTP trust | SDK transport security + config.mcp allowlists | ad-hoc Origin checks or trusted forwarded headers |
| Local MCP/A2A jobs | LocalJobSupervisor + SingleJobStore | a second worker, scheduler, or lifecycle journal |
HTTP is deliberately multi-client (browser → curl_cffi → httpx → requests → urllib) for scrape-tier evasion - that set is closed. A sixth client is a reviewed exception, not a default. If you genuinely need a new pattern, add the seam and migrate callers - don't leave two ways behind.
</details>Negative Constraints
What NOT to do. These are gated or will fail review:
- NEVER add a second way to do something that already has a seam (above).
- NEVER let a monster file grow. A new file over ~800 lines needs a split
plan; the large files (
research_agent.py,cli.py,deep_research.py, …) are pinned bytests/test_architecture.pyand may not grow - split instead of raising the ceiling. - NEVER trust training memory for "now." Verify the current library
version, API signature, and model ID (against
uv.lock/config/models.py/ current docs) before using them. Stale/deprecated APIs and hallucinated packages are a top AI-code failure mode - assume your recall is six months stale and confirm. - NEVER bypass the SSRF guard. Every outbound URL goes through
utils.security.is_safe_url(validated post-redirect); untrusted scraped text entering a prompt is fenced viautils.content_sanitizer.fence_untrusted. No secrets in code, logs, or fixtures. - NEVER launch a billable run without an estimate + explicit approval -
primr runs cost real money and time; the cost gate is non-negotiable (this is
the operate-side contract in
clients/primr-operator.md, restated here as a design boundary). - NEVER turn primr into a daemon / always-on watcher - it is single-job by design (URL in, artifact out). Loops and scheduling live on the consumer side; do not add a background watcher to the core.
- NEVER put real company data anywhere that ships (docs, fixtures, commit
messages) - use
Acme Corp/ExampleCo/acme.example. See CONTRIBUTING. - NEVER add non-human authorship or provenance lines to commits, PR bodies, or comments. Avoid coauthor trailers, AI-generation credits, or tool-credit language for any AI, bot, or automation tool. Every commit reads as a human engineer's work.
- Keep dependencies justified: never add an unimported or dead dependency
to
pyproject.toml. Heavy libraries used for narrow peripheral workflows belong in optional extras; core dependencies must be lean, safe, and imported. - Keep writing professional: no emojis, em dashes, or en dashes in new documentation, comments, generated text, commits, PRs, or delegated output.
Verification Commands
Use the existing environment with --no-sync during verification to avoid
implicit environment changes. Setup changes install dependencies; do not hide
them in a test command. primr doctor is optional environment diagnosis, not
proof of report quality or a substitute for tests.
uv run --no-sync primr --version
uv run --no-sync pytest tests/test_architecture.py -q<details>
<summary>Local release gate (same test scope and coverage floor as primary CI)</summary>uv run --no-sync ruff check src/primr/
uv run --no-sync ruff format --check src/ tests/
uv run --no-sync mypy src/primr/ --ignore-missing-imports --disable-error-code=import-untyped --exclude 'src/primr/api/'
uv run --no-sync mkdocs build --strict
uv run --no-sync bandit -r src/primr -c .bandit --severity-level medium --confidence-level medium -q
uv run --no-sync pip-audit
PRIMR_VALIDATE_SDIST=1 uv run --no-sync pytest tests/test_release_integrity.py::test_built_sdist_matches_release_inventory -q
GEMINI_API_KEY=fake-key-for-ci-tests uv run --no-sync pytest -q tests/test_core/test_resume_recovery.py tests/test_core/test_research_agent_resume.py tests/test_data/test_scrape_resume.py --cov=primr.core.cli --cov=primr.core.research_agent --cov=primr.data.scrape --cov-fail-under=13 --cov-report=term
GEMINI_API_KEY=fake-key-for-ci-tests uv run --no-sync pytest tests/ --ignore=tests/manual -x --tb=short -q -k "not test_wait_times_out_when_no_change" -m "not integration" --cov=src/primr --cov-branch --cov-fail-under=81The assignments above are POSIX syntax. In PowerShell use, for example,
$env:GEMINI_API_KEY = 'fake-key-for-ci-tests' before the command. Keep real
provider calls out of local tests; integration/manual runs require their normal
approval. The full command combines the five coverage shards in
.github/workflows/ci.yml; CI runs them sequentially with --cov-append and
enforces 81 percent only on the combined result. Use those exact shards when
isolating failures, not new exclusions. The separate recovery floor is 13
percent, not a replacement for global coverage. Non-primary interpreters omit
coverage; Windows/macOS CI also excludes the existing timing marker. Container
builds, Trivy, and other platform lanes remain separate CI evidence.
For portable plugin changes also run
uv run --no-sync python scripts/sync_agent_plugin.py --check and
uv run --no-sync pytest tests/test_agent_plugin.py -q. Fix the generator before
regenerating output. Dependency changes must regenerate both container lock
exports using the CI-pinned uv version; see docs/CONTRIBUTING.md.
Then ask the slop question: did this add a second way to do something that
already has a seam? If yes, fix it before review. Don't lower the coverage
ratchet; don't add a new ignore_errors mypy module (the strict allowlist only
grows). Pin load-bearing invariants with Hypothesis property tests.
</details>CLI verb convention
New user-facing capabilities are noun/verb subcommands
(primr <command> [args] [--modifiers]), matching recon/keys/mcp/
skills/update. Flags are modifiers, not commands. Legacy flag-commands
(--qa, --eval, …) keep back-compat aliases; don't add new ones.
Git / PR
Branch off main; keep PRs focused; update docs/CHANGELOG.md under
[Unreleased] for user-facing changes; keep the single version source of truth
consistent (pyproject ↔ __init__.__version__ ↔ ROADMAP "Current State" ↔
CITATION.cff, pinned by tests/test_release_integrity.py). Also update
claude-code/.claude-plugin/plugin.json and regenerate agent-plugin/plugin.json
with python scripts/sync_agent_plugin.py; run tests/test_agent_plugin.py
alongside the release integrity tests so plugin/package versions stay aligned.
Update the released baseline in docs/NEXT_STEPS.md and the OpenClaw image
version label; include tests/test_docs_index.py and
tests/openclaw/test_dockerfile.py in release metadata validation.
main is the only long-lived branch. Feature branches are short-lived and
deleted on merge (the repo auto-deletes merged PR branches); don't leave stale
branches behind. Merge via PR, not direct pushes to main.
Start tidy, stop tidy
Several agent tools may work here, and sessions can end partway through a task.
- Check first. Before new work, run
git fetch --pruneand reviewgit worktree list, local and remote branches, and open PRs. Finish, merge, or park leftover work instead of starting a parallel attempt. Squash merges hide merged work from ancestry, so check PR state, not onlygit branch --merged. - Checkpoint and hand off. Commit and push at meaningful checkpoints.
Before stopping, leave a short handoff (PR description, commit message, or
.agent/<task>/) stating what is done and what is next. - Keep the tree clean. Fixtures belong under
tests/; scratch scripts, logs, and generated output belong in.agent/or a temp directory. Remove scratch artifacts before finishing. - Goal state. One
mainwith CI passing; no work stranded on side branches. Push finished work, update or close PRs, close finished issues. - Remove only with evidence. Remove a worktree or branch only once its
work is merged, contained in
main, or pushed. Never--forcea removal; report anything uncertain instead.git worktree pruneis for entries whose directories are already gone. - Ask when unclear whether leftover work should be finished, kept, or removed.
An instruction-only refinement does not authorize commits, pushes, publishing, or deployment. Preserve the task's authorization and Primr's explicit spend gate.
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

