Spotlight is runtime-agnostic by design. Every subsystem is structured as a drop-in: add one directory or one table entry, and Spotlight picks it up. No central registration, no build step.
This doc is the entry point. It points at the per-subsystem contracts.
- Read
docs/structure.mdto understand the layout. - Read
AGENTS.md— the runtime contract every skill and agent speaks. - Run
bash tests/smoke.sh— if it passes on your machine, your environment is ready. - Check
docs/plans/for any active work-in-progress.
A runtime is an agent CLI or SDK (pi, Claude Code, Gemini, Codex, OpenCode, etc.) that can read AGENTS.md and dispatch the 13 verbs.
- Add the runtime as a choice in the local configurator: a radio card in
install/configure.html(cloud or local section) plus the matching handling ininstall/setup_server.py(normalize(),validate_choices,build_setup_config). The configurator carries choices only — no version strings. - Add the install/launch logic to
install-spotlight.sh. Version pins live ONLY ininstall-spotlight.shandVALIDATED_DEPENDENCIES.md— never duplicate them in the configurator. - Write
docs/runtimes.mdaddition — brief wiring notes, verb mapping specifics, sensitive-mode handling. - Run
bash tests/smoke.shandbash tests/eval.shto confirm consistency, plus the installer/configurator checks below.
An integration is a specific external OSINT tool (dev-browser, Junkipedia, OSINT Navigator, etc.).
mkdir integrations/<id>/- Write
integrations/<id>/manifest.jsonper the contract inintegrations/README.md. - Write
integrations/<id>/integration.md— when to use, verb calls, output format, sensitive-mode behavior. - Add a row to the routing table in
skills/integrations/SKILL.md. - Optional: add a checkbox to the Plug-ins section of the local configurator (
install/configure.html, wired throughinstall/setup_server.py) so journalists see it during install. - Run
python3 integrations/preflight.py --text— your new integration should appear.
Passive feed-source code moved to Mycroft. Do not add new monitoring feeds to Spotlight.
If you need a new passive source:
- Add it to Mycroft's monitoring service.
- Update Spotlight's monitoring references only if the orchestrator needs to know the source exists.
- Keep Spotlight focused on recommendation, approval, and cross-tool linkage.
A skill is a methodology playbook, not a tool — things like "how to investigate a person" or "how to archive evidence."
mkdir skills/<id>/- Write
skills/<id>/SKILL.mdwith YAML frontmatter:--- name: <id> description: <one-liner> version: "1.0" invocable_by: [investigator | fact-checker | orchestrator | user] requires: [<other-skill-id>] # optional ---
- Add a row to the skill registry in
AGENTS.md. - Reference the skill from
skills/spotlight/SKILL.mdor another orchestrator as appropriate. - Update
docs/structure.mdskill count. - Run
bash tests/smoke.sh— the skill-count check should now pass at the new total.
bash tests/smoke.sh # structural + cleanliness checks (fast, <2s)
bash tests/eval.sh # contract compliance + sample data validationCI runs both on every push + PR. Don't merge unless both are green.
When touching install-spotlight.sh, also run:
bash tests/install-spotlight-check.sh # bash -n + fragment assertions + landing-page checks
bash tests/install-spotlight-smoke.sh # --headless --dry-run combo matrixWhen touching the configurator (install/setup_server.py or install/configure.html):
python3 tests/configurator-server-check.py(See .github/workflows/ci.yml for the canonical test commands.)
- No new Claude-specific syntax in skills or agents. Use the 13 abstract verbs from
AGENTS.md. The smoke test greps forWebFetch,WebSearch,Agent(,Skill(,allowedTools,maxTurns, etc. and fails if any appear. - Every skill has YAML frontmatter with at least
name,description,version,invocable_by. - Every integration manifest declares
env_vars(empty array if none required) andrequires_key. - Generated files (scripts, JSON) must be validated.
tests/eval.shrunsjsonschemaon sample case files; add fixtures for new schemas. - No hardcoded personal emails or paths in committed code. Use env vars (
$UNPAYWALL_EMAIL, etc.) or configurable placeholders.
Short, imperative subject (50 chars) + blank line + body explaining the "why" (not the "what"). For breaking changes, lead the subject with !:.
Skip the Claude co-author trailer in PR commits — it's fine on main but noisy in PR review.
- Fork + branch from
main. - Keep PRs focused — one concern per PR. Splitting is better than bundling.
- Fill out
.github/PULL_REQUEST_TEMPLATE.md(auto-prompted on PR creation). - CI must pass (
tests/smoke.sh+tests/eval.sh). - For new runtimes / integrations / skills: include a brief
docs/addition + update the relevant registry. - Reviewer merges via squash-and-merge to keep
mainhistory linear.
If you find a security issue (credential leak pattern, API key exposure, arbitrary-code-execution in generated scripts, etc.), email [email protected] before filing a public issue. We'll coordinate disclosure.
Do NOT open a public issue for anything that could enable an attacker.
Non-trivial methodology contributions deserve attribution in the affected skill's frontmatter (attribution: field) and in LICENSE. We take journalism-methodology provenance seriously.
- General: open a GitHub Discussion
- Bugs: use the bug report issue template
- Features: use the feature request template
- Security: [email protected]