Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion skills/how-to-write-ideas-report/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ Write a structured ideas report after a `brainstorm-ideas` session has converged
Follow `skills/how-to-technical-writing/SKILL.md` for sentence- and paragraph-level prose rules. Follow `skills/how-to-write-ideas-report/references/writing-workflow.md` for context loading, citation handling, gap-filling research, output format, diagrams, and finish checks.

- Primary source: `docs/discussion/*-brainstorm-ideas-log.md`. If multiple logs exist and the request does not identify one, ask which to use.
- If no log exists, ask the user to brainstorm first or describe the chosen direction and reasoning to preserve.
- If no log exists, use the chosen direction and reasoning already in the conversation or supplied notes. Ask only for substance needed to write the requested report.
- Save to `articles/YYYY-MM-DD-<topic>-ideas-report.{md,typ,tex}` with a matching bibliography when citations are used.
- When entering from `brainstorm-ideas` Phase 3, carry forward the active conversation log, user profile, chosen direction, key references, and concrete action plan without asking the user to repeat them.

Expand Down
27 changes: 18 additions & 9 deletions skills/how-to-write-ideas-report/references/writing-workflow.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,25 +6,29 @@ Resolve the installed `how-to-download-ref` skill from the agent's catalog and s

## Context

- Resolve the project KB with `KB=$(python3 "$DOWNLOAD_REF_DIR/helpers/resolve_kb.py")`.
- If present, read `$KB/NOTES.md`, `$KB/INDEX.md`, and the canonical bib `$KB/references.bib`.
Start from what the user supplied: text, source files, scope, format, and any
authorization already given. A local prose edit needs the passage plus the
definitions and citations it depends on, not the whole KB or conversation history.

- Resolve the project KB when KB-backed context is needed: `KB=$(python3 "$DOWNLOAD_REF_DIR/helpers/resolve_kb.py")`.
- Read `$KB/INDEX.md` and `$KB/NOTES.md` for the topic, then the relevant notes and bibliography entries. Screening the whole bibliography belongs to an explicitly selected review.
- Read `docs/discussion/user-profile.md` when audience, background, or positioning matters.
- For ideas/manuscripts, read relevant `docs/discussion/*-brainstorm-ideas-log.md`.
- If the needed literature base is missing, suggest the `survey` skill or ask the user for explicit source files.
- For ideas/manuscripts, read the relevant `docs/discussion/*-brainstorm-ideas-log.md`, starting from the wrap-up section.
- Papers the user supplied and a manuscript-local bibliography are valid sources without a sci-brain KB. If the needed literature base is missing, suggest the `survey` skill or ask the user for explicit source files.

The canonical bib is `$KB/references.bib`.

**Legacy compatibility.** Pre-0.3 KBs kept the bib at the project root as `$(dirname $KB)/ref.bib`. If `$KB/references.bib` is absent but that legacy file exists, use it for this run and offer to migrate it (`git mv "$(dirname $KB)/ref.bib" "$KB/references.bib"`) so future runs find it in the canonical spot. If neither exists, glob `$KB/*.bib` and confirm with the user before using another file.

## Scope the source set

A write-up covers a *subset* of the bib — the references the relevant `NOTES.md` section(s) actually cite, not all 100+ accumulated entries. Determine that subset deterministically instead of by eye:
For a KB-backed report, a write-up covers a *subset* of the bib — the references the relevant `NOTES.md` section(s) actually cite, not all 100+ accumulated entries. Determine that subset deterministically instead of by eye:

```sh
python3 "$DOWNLOAD_REF_DIR/helpers/scope_refs.py" --notes "$KB/NOTES.md" --bib "$KB/references.bib"
```

It prints the scoped cite keys (one per line) and exits non-zero if any `[@key]` anchor in the notes has no bib entry — fix dangling anchors before drafting. Use `--json` for `{scoped, missing, unused}`. Draft against the scoped keys; the `unused` list is out of scope unless the user asks to widen it.
When the user supplied explicit sources instead, use those directly; do not require NOTES.md. The helper prints the scoped cite keys (one per line) and exits non-zero if any `[@key]` anchor in the notes has no bib entry — fix dangling anchors before drafting. Use `--json` for `{scoped, missing, unused}`. Draft against the scoped keys; the `unused` list is out of scope unless the user asks to widen it.

## References

Expand Down Expand Up @@ -61,11 +65,16 @@ For Typst, prefer native `grid` + `rect` + fixed-width `box()` for text-heavy la

Run these checks before declaring the document done — do not eyeball them:

- **Compile** the document (`typst compile <file>.typ`, or the LaTeX/Markdown equivalent) and confirm it exits cleanly.
- **No dangling citations.** Grep the compile log for unresolved-reference warnings; for Typst, a missing key warns rather than errors, so an empty grep is the pass condition:
- **Compile** the document and check both the exit status and the log. For Typst, a missing cite key only warns, so a clean exit alone is not a pass; the block below fails on a nonzero exit *or* on any warning, and prints the log either way (replace `main.typ` with the source file):
```sh
typst compile <file>.typ 2>&1 | grep -i "unresolved\|warning" || echo "clean"
LOG=$(mktemp)
typst compile main.typ >"$LOG" 2>&1; status=$?
cat "$LOG"
grep -Eiq 'unresolved|warning' "$LOG" && status=1
rm -f "$LOG"
[ "$status" -eq 0 ] && echo clean
```
Use the LaTeX/Markdown equivalent for other formats. Read every warning before calling the build clean.
- **Every scoped claim is cited.** Confirm each `@key` in the prose resolves to a bib entry and that no scoped key was silently dropped (cross-check against `scope_refs.py` output).
- **Non-empty bibliography** renders in the output.
- Report the output path and any skipped verification.
57 changes: 57 additions & 0 deletions tests/test_writing_workflow.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
"""Execute the documented Typst build check against realistic outcomes."""

import os
import re
import subprocess
from pathlib import Path

import pytest


ROOT = Path(__file__).resolve().parents[1]


@pytest.mark.parametrize(
"compiler_exit,diagnostic,expected_exit",
[
(0, "", 0),
(0, "warning: unresolved citation", 1),
(2, "error: unknown variable", 1),
(127, "compiler unavailable", 1),
],
)
def test_documented_compile_check_handles_failure_and_warnings(
tmp_path, compiler_exit, diagnostic, expected_exit
):
workflow = (
ROOT / "skills/how-to-write-ideas-report/references/writing-workflow.md"
).read_text()
blocks = re.findall(r"```sh\n(.*?)\n\s*```", workflow, re.DOTALL)
checks = [block for block in blocks if "typst compile" in block]
assert len(checks) == 1

compiler = tmp_path / "typst"
compiler.write_text(
'#!/bin/sh\nprintf "%s\\n" "$TEST_DIAGNOSTIC" >&2\n'
'exit "$TEST_COMPILER_EXIT"\n'
)
compiler.chmod(0o755)
logs = tmp_path / "logs"
logs.mkdir()
env = {
**os.environ,
"PATH": str(tmp_path) + os.pathsep + os.environ["PATH"],
"TMPDIR": str(logs),
"TEST_DIAGNOSTIC": diagnostic,
"TEST_COMPILER_EXIT": str(compiler_exit),
}
result = subprocess.run(
["/bin/sh", "-c", checks[0]],
cwd=tmp_path,
env=env,
capture_output=True,
text=True,
)
assert result.returncode == expected_exit, result
assert diagnostic in result.stdout + result.stderr
assert not list(logs.iterdir()), "temporary compiler log was not removed"
Loading