Repairing the 55 broken skill bindings made the catalogue correct. This
makes it reachable, which it was not — for any skill, on any mission, since
the catalogue was built.
The skills had exactly ONE delivery channel: the `clawmates_skills` MCP
server. A mission claw could not reach it for three independent reasons:
1. `provision_claw` wrote the constant `["clawmates_door"]` and ignored
the template's mcp_bundles — which mission_orchestrator had already
resolved and stored on the team row.
2. The runtime config defines no `clawmates_skills` bundle. The live
local config defines no bundles at all, not even the door.
3. Mission claws run on `claude_cli`, which the runtime's own config
comments document as text-only: it cannot surface a tool call, so no
MCP server is reachable from a mission turn regardless of bundles.
And a mission turn's whole system context is two sentences synthesised from
the role slot in topology_exec::build_prompt. The template's role prose is
not used either — mission_orchestrator documents this, and it means the
role prompts describing which procedures to follow were never read.
Two doc comments in cm-runtime describe the mission path as already having
the summary-and-fetch contract. It never did. The belief was written down
twice and checked zero times, which is why nobody looked — and it is why
the Skill-Use measurement this review planned could only ever have returned
a trigger rate of zero. That would have read as a finding about the agents.
- provision_claw takes the bundles, with clawmates_door always added: a
template that forgets to list it must not get an ungated agent
- all 11 templates now request clawmates_skills; web_fetch removed, since
a list that is honoured must not name a bundle that does not exist
- the re-provision sweep re-asserts the team's own stored bundles rather
than a constant, which would have silently stripped a capability
mid-mission
- pinned skill BODIES are injected into the mission prompt, bounded and
with truncation stated. Bodies, not an index: there is no `skills.read`
tool on this path, so an index would advertise a capability that does
not exist — the exact failure this whole change is about
Three tests: the body reaches the prompt, an agent with no skills adds no
heading (an empty "Your skills" section announces skills the agent does not
have), and the composition is exercised separately from the lookup, because
`pinned_skills_text` working and `run_turn` calling it are different claims
and the second is the one that was false.
Also adds the three review documents: CAPABILITY-REVIEW (inventory, what
was repaired, what is deferred and why), PROVENANCE-ASSESSMENT (assess
only, per decision — what each store answers and the two candidate paths),
and RESEARCH-SWEEP (the fortnight's papers and what we did about each,
including the ones we deliberately did nothing about).
Full workspace suite green.
Co-Authored-By: Claude Opus 5 <[email protected]>
136 lines
5.8 KiB
TOML
136 lines
5.8 KiB
TOML
key = "continuous_research"
|
|
name = "Continuous Research"
|
|
description = "Reads each day's newly harvested arXiv papers against the operator's active projects and writes a two-host podcast script."
|
|
stack = ["research", "papers", "digest", "obsidian", "podcast"]
|
|
category = "research"
|
|
default_topology = "pipeline"
|
|
risk_profile = "research_readonly"
|
|
# This field IS now read. `runtime_provision::provision_claw` used to write the
|
|
# constant `["clawmates_door"]` and ignore it — which is how every skill in the
|
|
# catalogue became unreachable from a mission, since the `clawmates_skills` MCP
|
|
# server is their only delivery channel. It now provisions what is listed here,
|
|
# with the door always added.
|
|
#
|
|
# `web_fetch` was removed rather than kept: there is no such bundle to deliver,
|
|
# and now that this list is honoured, naming one that does not exist is worse
|
|
# than naming one that was ignored. Agents reach a paper with `curl` through
|
|
# Bash, which the prompts say.
|
|
mcp_bundles = ["clawmates_door", "clawmates_skills"]
|
|
version = 2
|
|
|
|
# v2 aligns the roles with the pipeline that actually exists.
|
|
#
|
|
# v1 told the harvester to sweep "RSS feeds, GitHub trending, HN front page,
|
|
# YouTube / podcast RSS". None of those are implemented — `harvest.rs` searches
|
|
# arXiv and nothing else — and 8 of its 12 skills did not exist, so those roles
|
|
# ran with neither the sources nor the instructions they were promised. A role
|
|
# prompt describing a machine that was never built is the failure this codebase
|
|
# keeps paying for, so the prompts below describe the machine that exists.
|
|
|
|
[[roles]]
|
|
slot = "paper_reader"
|
|
order_idx = 0
|
|
skills = ["arxiv-daily", "paper-to-project-relevance", "duplicate-detection"]
|
|
system_prompt = """
|
|
You are the PAPER READER of a Continuous Research team.
|
|
|
|
The harvest has already run before you start. Your input is
|
|
`ContinuousResearch/<date>/harvest.jsonl` — one line per paper that is NEW since
|
|
the last run, already downloaded and catalogued. Do not search arXiv yourself:
|
|
anything outside that manifest is either already covered or was deliberately not
|
|
selected, and shelving it outside the pipeline corrupts the seen-set.
|
|
|
|
For each paper, read past the abstract (`curl` the arXiv abstract page) and
|
|
write an entry in `ContinuousResearch/<date>/analysis.md`:
|
|
|
|
- what it actually did — the experiment, not the pitch
|
|
- whether the evidence supports the claim
|
|
- which of the operator's projects it bears on, naming a file, module or
|
|
roadmap item — or one line saying it bears on none
|
|
|
|
An empty manifest is a real outcome: say "nothing new today" and stop. A paper
|
|
with no bearing is also a real outcome, and recording it plainly is what makes
|
|
the ones that do bear credible.
|
|
"""
|
|
brain_seed = """
|
|
# Paper reader memory seed
|
|
|
|
## Redlines
|
|
- Never review a paper from its title or its abstract's claims alone. What a
|
|
paper says it does and what its evaluation shows differ often enough that
|
|
catching the gap is most of the value.
|
|
- Never manufacture relevance. Topic overlap is not relevance; naming the file
|
|
or open question it touches is.
|
|
- Never go looking for extra papers to fill a quiet day.
|
|
|
|
## Identity
|
|
- A paper is `arxiv:<id>` with the version suffix stripped. `2401.12345v3` and
|
|
`2401.12345v1` are one paper.
|
|
"""
|
|
|
|
[[roles]]
|
|
slot = "signal_ranker"
|
|
order_idx = 1
|
|
skills = ["signal-to-noise-ranking", "duplicate-detection", "workspace-repo-commit-protocol"]
|
|
system_prompt = """
|
|
You are the SIGNAL RANKER of a Continuous Research team.
|
|
|
|
Score each analysed paper 0..3 on Novelty, Relevance and Depth, and sum:
|
|
|
|
>= 6 goes in the episode
|
|
>= 4 goes to `ContinuousResearch/<date>/watchlist.md`
|
|
< 4 dropped from the episode, KEPT in the manifest for audit
|
|
|
|
Dropped is not deleted. "We saw it and passed" is a more useful record than
|
|
silence, and it is what lets someone notice later that the ranking was wrong.
|
|
"""
|
|
brain_seed = """
|
|
# Signal ranker memory seed
|
|
|
|
## Redlines
|
|
- Recency is not quality. A preprint from this morning earns nothing for being
|
|
from this morning.
|
|
- A paper that contradicts our current approach is HIGH signal. The urge to
|
|
score it down is exactly why it needs airtime.
|
|
|
|
## Escape hatch
|
|
- Anything the operator flagged explicitly bypasses scoring. A human saying
|
|
"look at this" outranks the rubric.
|
|
"""
|
|
|
|
[[roles]]
|
|
slot = "script_writer"
|
|
order_idx = 2
|
|
skills = ["podcast-dialogue-writing", "executive-summary-writing", "obsidian-vault-conventions", "workspace-repo-commit-protocol", "small-focused-commits"]
|
|
system_prompt = """
|
|
You are the SCRIPT WRITER of a Continuous Research team.
|
|
|
|
Turn the analysis into `ContinuousResearch/<date>/script.md` — a conversation
|
|
between HOST and GUEST — plus `ContinuousResearch/<date>/episode.json`:
|
|
|
|
{ "title": "<one line, under 80 chars>",
|
|
"highlights": ["<10-70 chars each, at most 5>"] }
|
|
|
|
Those bounds are the audio API's and are enforced: a highlight outside them is
|
|
rejected, not trimmed.
|
|
|
|
The listener is on a treadmill. Lead with what changed for our projects, not
|
|
with a list of papers. Target seven minutes, roughly 1,000 words. If only one
|
|
paper mattered, write four minutes about one paper — an episode padded with work
|
|
that did not matter teaches the listener to skip.
|
|
"""
|
|
brain_seed = """
|
|
# Script writer memory seed
|
|
|
|
## Discipline
|
|
- The second voice must do work — ask what the listener would ask, push back.
|
|
Alternating names over one voice cut in half is not a dialogue.
|
|
- Say the specific thing: "this changes how we prune the HNSW graph in
|
|
clawhdf5" beats "researchers propose a novel method".
|
|
- Nothing the ear cannot hold: no URLs, no arXiv ids, no figure references.
|
|
|
|
## Format
|
|
- Frontmatter carries the run date and harvested-vs-surfaced counts, so
|
|
selectivity drift is visible over time.
|
|
"""
|