backup materials and knowledge-base docs

This commit is contained in:
admin
2026-05-30 16:22:29 +08:00
commit 93e50e8fce
3024 changed files with 2994945 additions and 0 deletions

View File

@@ -0,0 +1,50 @@
---
name: zotero-obsidian-bridge
description: Use this skill when Zotero is the literature source of truth and the project KB should receive source notes under Sources/Papers plus project-linked synthesis in Knowledge and Writing.
version: 0.3.0
---
# Zotero Obsidian Bridge
Use this skill when papers live in Zotero and the project KB should receive project-local notes.
Default flow:
```text
Zotero -> Sources/Papers -> Knowledge -> Writing -> Maps/literature.canvas
```
Rules:
- one canonical paper note per paper under `Sources/Papers/`
- literature synthesis goes to `Knowledge/`
- writing-oriented outputs go to `Writing/`
- `Maps/literature.canvas` is the default derived graph artifact
- update `_system/registry.md`, `02-Index.md`, and today's `Daily/` after substantial ingestion
## Evidence extraction requirement
Core papers and papers with reusable claims should include an evidence record. Abstract-only or placeholder notes may stay in `To-Read` until there is enough evidence to extract a reusable claim.
```md
## Evidence Record
Evidence ID:
Source:
Source type: full paper | preprint | dataset | experiment artifact | project note | abstract-only | webpage placeholder
Supports:
Contradicts:
Method / dataset / metric:
Limitation:
Project relevance:
Claim strength: speculative | observed | supported | strong
```
Use `../research-ideation/references/research-contract.md` as the shared contract for Evidence Records and claim strength definitions.
Before synthesis lands in `Knowledge/` or `Writing/`, apply the shared Claim Promotion Gate:
- every promoted claim must point back to an Evidence Record ID,
- source type must be strong enough for the claim,
- abstract-only and webpage-placeholder items cannot support durable claims,
- allowed wording and forbidden stronger wording must be preserved when the claim may later enter a report, manuscript, or rebuttal.
When synthesis lands in `Knowledge/`, link the supporting paper notes explicitly. Do not promote literature synthesis that cannot point back to source notes.

View File

@@ -0,0 +1,27 @@
---
type: zotero-collection-inventory
collection: Cross Subject
collection_slug: cross-subject
source: zotero
coverage_expected: 3
coverage_actual: 3
updated: 2026-03-18T00:00:00Z
---
# Cross Subject Inventory
## Coverage Summary
- Expected items: 3
- Canonical notes: 3 / 3
## Item Mapping
| Zotero Key | Item Title | Canonical Note | Status |
|---|---|---|---|
| ABCDEFGH | Shared Latent Geometry for Cross-Subject Speech Decoding | Sources/Papers/Shared-Latent-Geometry.md | covered |
| HGFEDCBA | Domain Adapters for Neural Transfer | Sources/Papers/Domain-Adapters.md | covered |
| ZXCVBNML | Contrastive Transfer under Low Resource Conditions | Sources/Papers/Contrastive-Transfer.md | covered |
## Triage
- fully covered: 3
- bridge-only: 0
- needs-review: 0

View File

@@ -0,0 +1,49 @@
# Collection Inventory Schema
Use this note when a Zotero collection is imported or audited at collection scope.
## Canonical path
```text
Knowledge/Zotero-Collection-{collection-slug}-Inventory.md
```
## Frontmatter
```yaml
---
type: zotero-collection-inventory
collection: Cross Subject
collection_slug: cross-subject
source: zotero
coverage_expected: 16
coverage_actual: 16
updated: 2026-03-18T00:00:00Z
---
```
## Required sections
```markdown
# Cross Subject Inventory
## Coverage Summary
- Expected items: 16
- Canonical notes: 16 / 16
## Item Mapping
| Zotero Key | Item Title | Canonical Note | Status |
|---|---|---|---|
| ABCDEFGH | Example title | Sources/Papers/Example-Paper.md | covered |
## Triage
- fully covered
- skipped or bridge-only notes
- items that still need full notes
```
## Rules
- Keep one durable inventory note per collection slug.
- `Canonical Note` should use project-relative note paths.
- `Status` should use a small vocabulary such as `covered`, `bridge-only`, `skipped`, `needs-review`.
- Update coverage counts whenever the collection is batch-processed again.

View File

@@ -0,0 +1,22 @@
# Local Zotero Fallback
Use this runbook when the Zotero MCP transport is unavailable but the user still wants a collection-level pass.
## Preconditions
- A local `zotero-mcp` checkout or installed Python package is available.
- The local environment can read metadata/fulltext without mutating the Zotero library.
## Default fallback sequence
1. Confirm that MCP transport is the failing layer, not the collection query itself.
2. Switch to the local Python-backed path for metadata and fulltext retrieval.
3. Continue creating or updating canonical paper notes.
4. Run `verify_paper_notes.py` before closing the batch.
## Report explicitly
Always state:
- that MCP transport failed,
- that the workflow continued through local fallback,
- what remained unavailable, if anything.

View File

@@ -0,0 +1,85 @@
# Zotero-Sourced Paper Note Schema
## Frontmatter
```yaml
---
type: paper
project: project-slug
title: "Paper Title"
canvas_visibility: hidden
authors:
- Author A
- Author B
year: 2026
venue: "NeurIPS"
doi: "10.xxxx/xxxxx"
url: "https://doi.org/..."
citekey: "author2026paper"
zotero_key: "ABCDEFGH"
status: read
source_type: full paper
claim_strength: observed
keywords:
- subject-invariance
- contrastive-learning
concepts:
- shared geometry
methods:
- contrastive pretraining
subfield: speech-transfer
related_papers:
- "Sources/Papers/Another-Paper"
linked_knowledge:
- "Knowledge/Literature Overview"
- "Knowledge/Method Taxonomy"
argument_claims:
- "Shared geometry exists but is fragile"
argument_methods:
- "Geometry-aware transfer"
argument_gaps:
- "Still needs speech-specific validation"
paper_relationships:
- "Sources/Papers/Another-Paper::complements"
updated: 2026-03-16T00:00:00Z
---
```
## Sections
```markdown
# Paper Title
## Claim
## Research question
## Method
## Evidence
Use the shared Evidence Record shape from `research-ideation/references/research-contract.md`.
## Strengths
## Limitation
## Direct relevance to repo
## Relation to other papers
## Knowledge links
## Optional downstream hooks
- Writing:
```
## Rules
- `related_papers` and `linked_knowledge` should prefer project-relative note paths.
- `paper_relationships` should record explicit semantic edges only when they are stable enough to support graph construction.
- `concepts` and `methods` may remain plain strings; do not create dedicated notes by default.
- Keep `Direct relevance to repo` concrete and actionable.
- Prefer one durable canonical note per paper; update in place instead of making sibling notes.
- If the user asked for a full collection pass, normalize the schema across the entire covered set before closing the task.
- Treat Zotero `webpage` items as weak-source inputs by default. If they are abstract-only or placeholder pages, set `source_type: webpage placeholder` or `source_type: abstract-only`, keep `status: to-read`, and do not use them to support `Knowledge`, manuscript, or rebuttal claims.

View File

@@ -0,0 +1,90 @@
# Zotero -> Obsidian Workflow
## 1. Resolve the project
1. Run the Obsidian project-memory detect flow.
2. If the repo is bound, use its `Research/{project-slug}/` vault root.
3. If not bound but clearly a research repo, bootstrap first.
## 2. Read from Zotero
Preferred read path per paper:
1. `zotero_get_item_metadata`
2. `zotero_get_item_fulltext`
3. `zotero_get_annotations`
4. `zotero_get_notes`
Use metadata + abstract as the minimum fallback when PDF full text is unavailable.
If the MCP transport path is broken but a local `zotero-mcp` source checkout is available, use the local Python fallback to call the same metadata/fulltext functions instead of aborting.
Treat Zotero `webpage` items as weak-source entries unless they clearly expose full paper metadata and useful fulltext. Abstract-only pages and webpage placeholders may be kept for discovery, but they must remain `To-Read` or `weak-source` and cannot support `Knowledge` or manuscript claims until replaced by a full paper, preprint, or verified artifact.
## 3. Create/update the canonical paper note
Canonical destination:
- `Sources/Papers/{normalized-title-or-citekey}.md`
Update instead of duplicating when the note already exists.
## 4. Detailed reading note requirements
Each durable paper note should contain:
- claim
- research question / problem
- method
- evidence
- strengths
- limitation
- direct relevance to repo
- links to related papers and the best matching `Knowledge/` notes
## 5. Synthesize the stable literature knowledge
After a batch import, prefer agent-first synthesis into `Knowledge/`:
1. update `Knowledge/Literature Overview.md` when the batch yields a stable overview
2. update `Knowledge/Method Taxonomy.md` when method clusters are clear
3. update `Knowledge/Research Gaps.md` when open problems or tensions are stable enough to keep
4. if the source is a named Zotero collection, update a durable inventory note that records:
- collection size,
- triage buckets,
- collection item -> canonical note mapping,
- current coverage such as `16 / 16`
Apply the Claim Promotion Gate before creating or updating `Knowledge/`:
- every stable claim must cite a canonical paper note and an Evidence Record ID,
- `speculative` and `observed` claims stay as hypotheses, motivations, or open gaps,
- abstract-only or webpage-placeholder items can appear in coverage notes but not as support for durable conclusions,
- if the batch lacks enough evidence records, produce a warning/claim map instead of a polished synthesis.
## 6. Refresh the default literature canvas
After batch note creation or major note updates:
1. rebuild `Maps/literature.canvas`
2. ensure core paper notes have meaningful wikilinks into `Knowledge/`
3. keep the graph lightweight and project-facing
4. prefer semantic filtering and edge thinning over dense all-to-all paper links
5. prefer `paper + claim + method + gap` argument-map structure for the main graph
6. add `Maps/literature-main.canvas` only when a second lightweight display graph is genuinely useful
7. preserve edge evidence strength where possible; do not create all-to-all paper links or stable-looking claim edges without source-note support
## 7. Push downstream only when justified
- during Zotero ingestion, default to `Sources/Papers/` plus `Knowledge/`
- update `Writing/` only when the user asks for a review, comparison, or draft-facing synthesis and the promoted claims pass the Claim Promotion Gate
- treat `Experiments/` and `Results/` as later project workflows, not default Zotero-import targets
## 8. Verify before closing
After batch ingestion or schema refactors:
1. verify every expected paper has a canonical note
2. verify `zotero_key` coverage matches the imported collection
3. verify all covered notes use the same canonical section schema
4. update the project `Daily/` note and project memory with what changed
Recommended verification command:
```bash
python3 "${CLAUDE_PLUGIN_ROOT}/skills/zotero-obsidian-bridge/scripts/verify_paper_notes.py" \
--papers-dir "/absolute/path/to/Sources/Papers" \
--expected-zotero-keys "KEY1,KEY2,KEY3" \
--inventory-note "/absolute/path/to/Knowledge/Zotero-Collection-collection-slug-Inventory.md"
```

View File

@@ -0,0 +1,212 @@
#!/usr/bin/env python3
"""Verify Obsidian paper-note schema, Zotero-key coverage, and optional inventory consistency."""
from __future__ import annotations
import argparse
import re
import sys
from pathlib import Path
REQUIRED_HEADINGS = (
"## Claim",
"## Method",
"## Evidence",
"## Limitation",
"## Direct relevance to repo",
"## Relation to other papers",
)
REQUIRED_FRONTMATTER_FIELDS = (
"type",
"project",
"title",
"zotero_key",
"linked_knowledge",
"paper_relationships",
"updated",
)
ZOTERO_KEY_RE = re.compile(r'^zotero_key:\s*"?([A-Z0-9]+)"?', re.MULTILINE)
FRONTMATTER_RE = re.compile(r'^---\n(.*?)\n---\n', re.DOTALL)
FIELD_RE_TEMPLATE = r'^{}:\s*'
INVENTORY_ROW_RE = re.compile(r'^\|\s*([A-Z0-9]+)\s*\|\s*(.*?)\|\s*(.*?)\|\s*(.*?)\|\s*$')
def parse_args() -> argparse.Namespace:
parser = argparse.ArgumentParser(
description="Verify paper-note schema and optional Zotero-key / inventory coverage."
)
parser.add_argument("--papers-dir", required=True, help="Directory containing canonical paper notes.")
parser.add_argument(
"--expected-zotero-keys",
default="",
help="Comma-separated Zotero keys expected to be covered.",
)
parser.add_argument(
"--inventory-note",
default="",
help="Optional collection inventory note to cross-check against canonical paper notes.",
)
parser.add_argument(
"--strict-missing-zotero-key",
action="store_true",
help="Treat notes without zotero_key as errors. Default behavior skips them.",
)
return parser.parse_args()
def load_expected_keys(raw_keys: str) -> list[str]:
if not raw_keys.strip():
return []
return [key.strip() for key in raw_keys.split(",") if key.strip()]
def extract_frontmatter(text: str) -> str:
match = FRONTMATTER_RE.match(text)
return match.group(1) if match else ""
def missing_frontmatter_fields(frontmatter: str) -> list[str]:
missing: list[str] = []
for field in REQUIRED_FRONTMATTER_FIELDS:
if not re.search(FIELD_RE_TEMPLATE.format(re.escape(field)), frontmatter, re.MULTILINE):
missing.append(field)
return missing
def collect_note_status(
papers_dir: Path,
strict_missing_zotero_key: bool,
) -> tuple[dict[str, str], list[str], list[str]]:
key_to_file: dict[str, str] = {}
issues: list[str] = []
skipped_without_key: list[str] = []
for path in sorted(papers_dir.glob("*.md")):
text = path.read_text(encoding="utf-8")
frontmatter = extract_frontmatter(text)
match = ZOTERO_KEY_RE.search(text)
if not match:
skipped_without_key.append(path.name)
if strict_missing_zotero_key:
issues.append(f"{path.name}: missing zotero_key")
continue
zotero_key = match.group(1)
if zotero_key in key_to_file:
issues.append(
f"{path.name}: duplicate zotero_key {zotero_key} also used by {key_to_file[zotero_key]}"
)
key_to_file[zotero_key] = path.name
missing_headings = [heading for heading in REQUIRED_HEADINGS if heading not in text]
if missing_headings:
issues.append(f"{path.name}: missing headings -> {', '.join(missing_headings)}")
missing_fields = missing_frontmatter_fields(frontmatter)
if missing_fields:
issues.append(f"{path.name}: missing frontmatter fields -> {', '.join(missing_fields)}")
return key_to_file, issues, skipped_without_key
def parse_inventory_note(inventory_path: Path) -> tuple[dict[str, str], list[str]]:
text = inventory_path.read_text(encoding="utf-8")
mapping: dict[str, str] = {}
issues: list[str] = []
in_table = False
for line in text.splitlines():
if line.strip() == "## Item Mapping":
in_table = True
continue
if in_table and line.startswith("## "):
break
if not in_table or not line.startswith("|"):
continue
if "---" in line:
continue
match = INVENTORY_ROW_RE.match(line)
if not match:
continue
key, _title, note_path, _status = [part.strip() for part in match.groups()]
if key in mapping:
issues.append(f"inventory: duplicate zotero key {key}")
mapping[key] = note_path
if not mapping:
issues.append("inventory: no item mapping rows found")
return mapping, issues
def main() -> int:
args = parse_args()
papers_dir = Path(args.papers_dir).expanduser()
expected_keys = load_expected_keys(args.expected_zotero_keys)
if not papers_dir.exists():
print(f"ERROR: papers dir not found: {papers_dir}")
return 1
note_files = list(papers_dir.glob("*.md"))
key_to_file, issues, skipped_without_key = collect_note_status(
papers_dir, args.strict_missing_zotero_key
)
print(f"Papers dir: {papers_dir}")
print(f"Paper notes scanned: {len(note_files)}")
print(f"Notes with zotero_key: {len(key_to_file)}")
if skipped_without_key:
print(f"Notes skipped without zotero_key: {len(skipped_without_key)}")
if expected_keys:
missing = [key for key in expected_keys if key not in key_to_file]
extras = sorted(set(key_to_file) - set(expected_keys))
print(f"Expected Zotero keys: {len(expected_keys)}")
print(f"Covered Zotero keys: {len(expected_keys) - len(missing)} / {len(expected_keys)}")
if missing:
issues.append(f"Missing expected keys: {', '.join(missing)}")
if extras:
print(f"Extra zotero_key notes: {', '.join(extras)}")
if args.inventory_note:
inventory_path = Path(args.inventory_note).expanduser()
if not inventory_path.exists():
issues.append(f"inventory note not found: {inventory_path}")
else:
inventory_mapping, inventory_issues = parse_inventory_note(inventory_path)
issues.extend(inventory_issues)
if inventory_mapping:
for key, note_path in inventory_mapping.items():
expected_name = key_to_file.get(key)
if expected_name is None:
issues.append(f"inventory: key {key} not found in paper notes")
continue
if Path(note_path).name != expected_name:
issues.append(
f"inventory: key {key} points to {note_path}, expected file ending {expected_name}"
)
missing_in_inventory = sorted(set(key_to_file) - set(inventory_mapping))
if missing_in_inventory:
issues.append(
f"inventory: missing keys present in paper notes -> {', '.join(missing_in_inventory)}"
)
if skipped_without_key:
print("Skipped note files without zotero_key:")
for name in skipped_without_key:
print(f"- {name}")
if issues:
print("\nISSUES:")
for issue in issues:
print(f"- {issue}")
return 1
print("\nOK: schema and coverage checks passed.")
return 0
if __name__ == "__main__":
sys.exit(main())