fix: close global writing profile review findings

This commit is contained in:
Mike Tsai
2026-08-26 00:35:19 +08:00
parent 248c2f80a0
commit 6234c0041c
6 changed files with 88 additions and 18 deletions
+2 -2
View File
@@ -598,9 +598,9 @@ Every skill's setup section should read:
Before drafting or rewriting natural-language Markdown, resolve the global config directory with the XDG/legacy algorithm above, then read `<global config dir>/WRITING.md` when it exists. A missing or empty `WRITING.md` means there are no custom writing preferences. If that optional read fails, warn and continue with the default framework guidance.
Apply writing guidance from the current project and the resolved vault's `AGENTS.md` over global `WRITING.md` preferences. Framework invariants including schema, provenance, safety, and operation-specific requirements — always take precedence over all writing preferences.
The effective precedence is framework invariants > current task/skill requirements > current project `AGENTS.md` > vault `AGENTS.md` > global `WRITING.md`. Framework invariants include schema, provenance, and safety; operation-specific requirements remain authoritative for the current task. Unspecified project and vault rules are inherited from less-specific layers, and more specific same-topic rules win.
Writing preferences apply only to newly drafted or rewritten natural-language fields and body content. They do not change YAML frontmatter, JSON, structured logs, or pass-through content, which retain their required formats and source fidelity.
Writing preferences apply only to newly drafted or rewritten natural-language fields and body content. This includes natural-language title and summary values in YAML frontmatter, but preferences cannot alter YAML syntax, required keys, structure, types, or machine-generated fields. JSON, structured logs, and pass-through content remain unchanged and retain their required formats and source fidelity.
## Environment Variables
+3 -3
View File
@@ -16,6 +16,9 @@ description: >
You are preserving knowledge from the current conversation as a permanent wiki note. The goal is to extract the *substance* — the knowledge itself — not a summary of what was said.
**Writing profile:** Before drafting or rewriting natural-language Markdown in any mode, read and apply the `Writing Profile Resolution` section in `llm-wiki/SKILL.md`. Framework schema, provenance, safety, and operation-specific requirements take precedence.
`WRITING.md` preferences apply only to newly drafted or rewritten natural-language Markdown; preserve source content and structured records.
This skill has three modes:
- **Full mode (default)** — classify the content and write a finished, cross-linked wiki page directly into the right category. This is the rest of this document (Steps 17).
@@ -99,9 +102,6 @@ After writing the derived correction, link the immutable source to the created/u
## Before You Start
**Writing profile:** Before drafting or rewriting natural-language Markdown, read and apply the `Writing Profile Resolution` section in `llm-wiki/SKILL.md`. Framework schema, provenance, safety, and operation-specific requirements take precedence.
`WRITING.md` preferences apply only to newly drafted or rewritten natural-language Markdown; preserve source content and structured records.
1. **Resolve config** — follow the Config Resolution Protocol in `llm-wiki/SKILL.md` (inline `@name` override → walk up CWD for `.env` → global config → prompt setup). This gives `OBSIDIAN_VAULT_PATH` and `OBSIDIAN_LINK_FORMAT` (default: `wikilink`).
2. Read `$OBSIDIAN_VAULT_PATH/index.md` to understand existing wiki content (avoid duplicates)
3. Read `$OBSIDIAN_VAULT_PATH/hot.md` if it exists — it gives context on recent activity
+38 -13
View File
@@ -62,26 +62,50 @@ If `.env` doesn't exist, create it from `.env.example`. Ask the user for:
- When enabled: all new/updated pages land in `_staging/` first; run `/wiki-stage-commit` to review and promote them
- `wiki-status` shows a "Staged writes pending" count when files are waiting
After resolving the global config directory using the Config Resolution Protocol in
`.skills/llm-wiki/SKILL.md`, create the shared writing profile only when it does not
After resolving config, assign the global config directory with the exact
`obsidian_wiki_config_dir` algorithm from the Config Resolution Protocol in
`.skills/llm-wiki/SKILL.md`. Create the shared writing profile only when it does not
already exist. Preserve an existing `$GLOBAL_CONFIG_DIR/WRITING.md`; never overwrite it
and do not ask additional writing-style questions.
Resolve the canonical template from `OBSIDIAN_WIKI_REPO` as follows:
Use `OBSIDIAN_WIKI_REPO` when it was loaded from config. When it is absent, derive the
absolute repository/data root from this loaded skill's absolute path, distinguishing the
packaged `<root>/skills/wiki-setup/SKILL.md` layout from the source
`<root>/.skills/wiki-setup/SKILL.md` layout. Then check both canonical template layouts:
- Packaged install: `$OBSIDIAN_WIKI_REPO/skills/llm-wiki/references/WRITING.md`
- Source checkout: `$OBSIDIAN_WIKI_REPO/.skills/llm-wiki/references/WRITING.md`
Copy the first layout whose template exists:
- Packaged install: `<root>/skills/llm-wiki/references/WRITING.md`
- Source checkout: `<root>/.skills/llm-wiki/references/WRITING.md`
```bash
GLOBAL_CONFIG_DIR="$(obsidian_wiki_config_dir)"
mkdir -p "$GLOBAL_CONFIG_DIR"
SKILL_FILE="<absolute path of this loaded wiki-setup/SKILL.md>"
SKILL_DIR="$(cd "$(dirname "$SKILL_FILE")" && pwd)"
if [ -n "${OBSIDIAN_WIKI_REPO:-}" ]; then
WIKI_ROOT="${OBSIDIAN_WIKI_REPO%/}"
else
case "$SKILL_DIR" in
*/.skills/wiki-setup) WIKI_ROOT="${SKILL_DIR%/.skills/wiki-setup}" ;;
*/skills/wiki-setup) WIKI_ROOT="${SKILL_DIR%/skills/wiki-setup}" ;;
*) echo "Cannot derive writing-profile template root from $SKILL_DIR" >&2; exit 1 ;;
esac
fi
WRITING_TEMPLATE=""
for candidate in \
"$WIKI_ROOT/skills/llm-wiki/references/WRITING.md" \
"$WIKI_ROOT/.skills/llm-wiki/references/WRITING.md"
do
if [ -f "$candidate" ]; then
WRITING_TEMPLATE="$candidate"
break
fi
done
[ -n "$WRITING_TEMPLATE" ] || { echo "Writing profile template not found under $WIKI_ROOT" >&2; exit 1; }
WRITING_PROFILE="$GLOBAL_CONFIG_DIR/WRITING.md"
if [ ! -e "$WRITING_PROFILE" ]; then
if [ -e "$OBSIDIAN_WIKI_REPO/skills/llm-wiki/references/WRITING.md" ]; then
WRITING_TEMPLATE="$OBSIDIAN_WIKI_REPO/skills/llm-wiki/references/WRITING.md"
else
WRITING_TEMPLATE="$OBSIDIAN_WIKI_REPO/.skills/llm-wiki/references/WRITING.md"
fi
cp "$WRITING_TEMPLATE" "$WRITING_PROFILE"
fi
```
@@ -218,9 +242,10 @@ Run a quick sanity check:
- [ ] `.env` has `OBSIDIAN_VAULT_PATH` set
- [ ] `.obsidian/` directory exists
- [ ] `_staging/` directory exists (required even when `WIKI_STAGED_WRITES` is not set — created on setup for future use)
- [ ] `WRITING_PROFILE` exists at the resolved global config directory
- [ ] Source directories (if configured) exist and are readable
Report the results and tell the user they can now:
Report the results, including the resolved absolute `WRITING_PROFILE` path, and tell the user they can now:
1. Open the vault in Obsidian (File → Open Vault → select the directory)
2. Run `wiki-status` to see what's available to ingest
3. Run `wiki-ingest` to add their first sources
+1
View File
@@ -297,6 +297,7 @@ echo "────────────────────────
echo " Setup complete!"
echo ""
echo " Skills found: $SKILL_COUNT"
echo " Writing profile: $WRITING_PROFILE"
echo " Agents ready: Claude Code, Cursor, Windsurf, Gemini CLI, Antigravity,"
echo " Codex, Hermes, OpenClaw, OpenCode, Aider, Factory Droid,"
echo " Trae, Trae CN, Kiro, Pi, GitHub Copilot (CLI + VS Code Chat)"
+3
View File
@@ -26,6 +26,9 @@ class SetupShDelegatesToCliTest(unittest.TestCase):
self.assertIn("WRITING.md", self.setup_sh)
self.assertIn("llm-wiki/references/WRITING.md", self.setup_sh)
def test_reports_resolved_writing_profile_path(self) -> None:
self.assertIn('Writing profile: $WRITING_PROFILE', self.setup_sh)
def test_calls_cli_module_not_a_standalone_git_flow(self) -> None:
self.assertIn("obsidian_wiki.cli", self.setup_sh)
+41
View File
@@ -34,6 +34,47 @@ def test_llm_wiki_defines_writing_profile_resolution() -> None:
assert "AGENTS.md" in body
def test_llm_wiki_defines_exact_precedence_and_inheritance() -> None:
body = (ROOT / ".skills" / "llm-wiki" / "SKILL.md").read_text()
assert (
"framework invariants > current task/skill requirements > current project "
"`AGENTS.md` > vault `AGENTS.md` > global `WRITING.md`"
) in body
assert "Unspecified project and vault rules are inherited" in body
assert "more specific same-topic rules win" in body
def test_llm_wiki_scopes_frontmatter_and_structured_content() -> None:
body = (ROOT / ".skills" / "llm-wiki" / "SKILL.md").read_text()
assert "natural-language title and summary values in YAML frontmatter" in body
assert (
"cannot alter YAML syntax, required keys, structure, types, or machine-generated fields"
) in body
assert "JSON, structured logs, and pass-through content remain unchanged" in body
def test_wiki_setup_resolves_global_path_and_template_without_repo_config() -> None:
body = (ROOT / ".skills" / "wiki-setup" / "SKILL.md").read_text()
assert 'GLOBAL_CONFIG_DIR="$(obsidian_wiki_config_dir)"' in body
assert 'SKILL_FILE="<absolute path of this loaded wiki-setup/SKILL.md>"' in body
assert 'if [ -n "${OBSIDIAN_WIKI_REPO:-}" ]; then' in body
assert "${SKILL_DIR%/skills/wiki-setup}" in body
assert "${SKILL_DIR%/.skills/wiki-setup}" in body
assert "/skills/llm-wiki/references/WRITING.md" in body
assert "/.skills/llm-wiki/references/WRITING.md" in body
def test_wiki_capture_applies_profile_before_every_mode() -> None:
body = (ROOT / ".skills" / "wiki-capture" / "SKILL.md").read_text()
hook = body.index("**Writing profile:**")
for heading in (
"## Quick Mode (`--quick`)",
"## Correction Mode (`--correction`)",
"## Full Mode",
):
assert hook < body.index(heading), heading
def test_every_current_prose_writer_references_the_contract() -> None:
for skill in REQUIRED_SKILLS:
body = (ROOT / ".skills" / skill / "SKILL.md").read_text()