Log → Dosu Knowledge
Product (keep it this simple):
- Read local agent logs
- Decide durable learnings (not the user’s prompt — the answer/gotcha found)
- Write each under a synthetic
dosu/log-backfill/<UTC-timestamp>
branch
(server auto-enqueues notes-upflow for that prefix — same path as a PR merge)
- Tell the user what was cached, expected token savings, and the backfill branch
- Open the HTML report (
generate_report.py --open
), including Estimated context savings
Dry-run: same extraction, but
do not call
. Output is
only the list of calls you
would make (with the synthetic branch filled in).
Requires a Dosu MCP connection with
. Writes must use
dosu/log-backfill/<timestamp>
so they auto-promote; do
not fall back to
the current checkout branch (those notes stay stranded until a real PR merges).
Do not ask (non-negotiable)
Never use AskUserQuestion / multiple-choice / “three scope decisions” for
this skill. Especially never ask:
- How notes should be attributed to branches (main / per-session / etc.)
- Note granularity / consolidation policy
- How far back to harvest (unless the user already asked and was ambiguous)
Fixed defaults — just run:
| Decision | Default |
|---|
| Time / volume | 50 most recent parent sessions |
| Branch on every | One BACKFILL_BRANCH=dosu/log-backfill/<UTC-timestamp>
for the whole run |
| Granularity | One durable learning per note (topic-shaped titles); consolidate in content when it’s the same fact |
The MCP tool schema saying “use
git branch --show-current
” does
not apply
here. Override it. Do not ask the user which branch to use. Inform them of
in one line after
, then continue.
- Setup: references/customer-setup.md
- What counts as a learning: references/write-criteria.md
- Log paths: references/history-locations.md
What a write looks like
Each learning is one MCP call. Args are exactly:
| Arg | Meaning |
|---|
| Noun-phrase topic (Slack PostgREST 1000-row channel picker cap
) |
| Self-contained fact a future agent needs |
| Literal git remote get-url origin
|
| Synthetic dosu/log-backfill/<UTC-YYYYMMDD-HHMMSS>
for the whole run |
| Optional, e.g. ["from-agent-log", "cursor"]
|
Wrong (never do this): using the user’s first message as
/ treating
inventory “write gaps” as the notes. Gaps are only which
sessions to open.
Right: after reading a digest, extract the durable conclusion, e.g.
title: Slack PostgREST 1000-row channel picker cap
content: slackChannel.getAll used an unbounded PostgREST select; hosted
PostgREST silently returns ≤1000 rows so large workspaces miss
channels that exist in slack.channel. Page the query.
repo: git@github.com:acme/api.git
branch: dosu/log-backfill/20260810-220015
Workflow
Progress:
- [ ] 0. whoami + REPO/BACKFILL_BRANCH/SKILL_DIR
- [ ] 1. Inventory (find sessions worth mining — internal)
- [ ] 2. Digest those sessions
- [ ] 3. Build the write_knowledge payload list (+ rediscovery token estimate)
- [ ] 4a. Default: write on BACKFILL_BRANCH (auto-promotes) → open HTML report (with estimated context savings) → reply
- [ ] 4b. Dry-run: print the payload list → stop (no writes, no finalize)
Step 0 — Target
bash
SKILL_DIR="$(find .claude/skills .cursor/skills .agents/skills \
-type d -name 'log-to-dosu-knowledge' 2>/dev/null | head -1)"
REPO="$(git remote get-url origin)"
BACKFILL_BRANCH="dosu/log-backfill/$(date -u +%Y%m%d-%H%M%S)"
test -f "$SKILL_DIR/scripts/parse_agent_logs.py"
Call
. Confirm
is available. One line to the user
which deployment will receive notes and the
for this run
(informational only — not a question). Never write log-backfill notes to the
checkout branch. Do not pause for branch / date-range / granularity choices.
Step 1 — Inventory (internal)
Default scope is the 50 most recent parent sessions. Override when the user asks:
| User says | Flags |
|---|
| (default) | (none — 50 most recent) |
| "last N days" / "past month" | (all sessions in that window) |
| "full audit" / "everything" | |
| "top N" / "N most recent" | |
bash
python3 "$SKILL_DIR/scripts/parse_agent_logs.py" \
--out /tmp/dosu-log-inventory.json
# examples:
# ... --days 30 --out /tmp/dosu-log-inventory.json
# ... --full --out /tmp/dosu-log-inventory.json
# ... --limit 100 --out /tmp/dosu-log-inventory.json
Use write-gap ids to pick digests. Do not show gap prompts as the result.
Step 2 — Digest
bash
python3 "$SKILL_DIR/scripts/parse_agent_logs.py" \
--digest <id> --json > /tmp/digest-<id>.json
Digest
every write-gap in the inventory for the chosen scope. Prefer parent
chats over
.
Step 3 — Build the write list
For each durable fact per write-criteria.md,
append a payload:
json
{
"title": "…",
"content": "…",
"repo": "<$REPO>",
"branch": "<$BACKFILL_BRANCH>",
"tags": ["from-agent-log", "cursor"],
"transcript_id": "<source session id>",
"approx_rediscovery_tokens": 12000
}
Use the same
for every candidate in the run. Do
not use
the checkout branch or a per-log branch name.
approx_rediscovery_tokens
is the analytics analogue of
page_version.generation_tokens
: tokens spent rediscovering this fact in the
source session (Read/Grep/Shell/etc. stretches that produced the learning).
Estimate when unsure:
- From inventory, take that transcript’s effective tokens × rediscovery share
(same fallback as : rediscovery_tool_calls / total tools,
capped at 0.85; ×0.5 if the session already had knowledge reads).
- Split that budget across notes mined from the same transcript.
Skip secrets/PII, task summaries, speculation, obvious one-file facts.
Write the full list to
/tmp/dosu-log-candidates.json
as
{ "candidates": [ …payloads… ] }
so dry-run, savings summary, and HTML share
one shape.
Step 4a — Default: write + savings
For each payload, call MCP
with
/
/
/
/
(omit helper fields like
approx_rediscovery_tokens
). Every
write must use
. The server auto-enqueues notes-upflow for
(same step as a PR merge) — no separate promote call.
If MCP write is unavailable:
bash
python3 "$SKILL_DIR/scripts/pending_knowledge.py" append \
--repo "$REPO" --branch "$BACKFILL_BRANCH" \
--title "…" --content "…" \
--tags from-agent-log,pending-sync
Then compute the default user-facing summary:
bash
python3 "$SKILL_DIR/scripts/summarize_savings.py" \
--candidates /tmp/dosu-log-candidates.json
That stdout is the default reply, plus one line that notes were written on
and entered the candidate-topic pipeline. Shape:
Cached N notes:
1. <title>
2. <title>
Expected savings: ~Y tokens per future agent read
(same model as analytics: rediscovery/generation cost reused on each hit)
Wrote on dosu/log-backfill/<UTC-YYYYMMDD-HHMMSS> (auto-promoted into the candidate-topic pipeline).
Do not stop at “Saved N notes” without the savings line.
Then always open the HTML report (not opt-in). Estimated context savings is filled from each note's
approx_rediscovery_tokens
— do not skip that field in step 3.
The reporter assumes notes were written; pass
only if generating HTML without write_knowledge.
bash
python3 "$SKILL_DIR/scripts/generate_report.py" \
--inventory /tmp/dosu-log-inventory.json \
--candidates /tmp/dosu-log-candidates.json \
--org-name "…" --repo "$REPO" --branch "$BACKFILL_BRANCH" \
--out /tmp/dosu-knowledge-report.html --open
Call
finalize_session_knowledge
once with write receipt ids if that tool exists.
Step 4b — Dry-run (when user asks)
Do not call
. Still set
and include it on
every listed payload. Reply with the payload list, e.g.:
Dry-run — would call write_knowledge N times:
1. title: …
content: …
repo: … branch: …
approx_rediscovery_tokens: …
2. title: …
content: …
repo: … branch: …
approx_rediscovery_tokens: …
That list
is the dry-run output. Not session prompts. Not inventory scores.
Optionally append the same
block (expected savings if
these were written). If you open the HTML on a dry-run, pass
.
Opt-in extras
| User says | Behavior |
|---|
| "PDF" | Print / Save as PDF from the HTML report already opened |
| "detailed token report" | Optional eval with pasted responses (overrides the default estimate) |
Guardrails
- Default writes on (server auto-promotes) and always
includes expected token savings, opens the HTML report, and fills Estimated context savings on that report.
- Never write log-backfill notes to the current checkout branch.
- Never ask how to attribute notes to branches — always .
- Never invent a scope questionnaire; use the defaults unless the user already
specified overrides in their message.
- Dry-run only when asked (no write).
- Never write secrets / PII / raw log dumps.
- One learning per call; keep notes lean.
- User-facing output is always about notes (written or proposed) + savings,
never raw prompts.
Quick examples
- "Please bootstrap my knowledge with Dosu." → write on backfill branch (auto-promotes) + cached titles + expected savings + open HTML report (with estimated context savings).
- "Mine my agent logs into Dosu." → same default write flow.
- "Dry-run log to dosu knowledge." → list of payloads (synthetic branch) only.