Skip to content
Open
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
21 changes: 21 additions & 0 deletions skills/.experimental/ivan-bazi-architect/LICENSE.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
MIT License

Copyright (c) 2026 Ivan

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
47 changes: 47 additions & 0 deletions skills/.experimental/ivan-bazi-architect/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
# Ivan Bazi Architect

Codex skill for BaZi-oriented decision diagnostics with indexed classical references.

## Resource Setup

Configure your local PDF source directory in a local `config.json` (copy from `config.example.json`):

```json
{
"source_dir": "/path/to/your/bazi-pdfs",
"output_format": "audit_memo",
"citation_mode": "book_file_snippet"
}
```

You can also pass `--source-dir` directly to the index script.

## Core References

- 三命通会(基础术语与多维意象)
- 穷通宝鉴(调候准则,SW-1)
- 滴天髓 / 子平真诠(能量流通与格局判定,SW-2)
- 八字提要(实战回退与执行指南)
- 周易译注(边界与可证伪框架)

## Quick Start

1. Build index:
- `python3 scripts/build_pdf_index.py --source-dir "/path/to/your/bazi-pdfs" --out references/pdf-index.jsonl`
- Or use config fallback: `python3 scripts/build_pdf_index.py --config config.json --out references/pdf-index.jsonl`
2. Invoke skill in Codex and request SW-1/SW-2/SW-3 diagnosis.
3. Ask for output in publish format (X thread / short brief / audit memo).

## Install In Codex

`$skill-installer install https://github.com/openai/skills/tree/main/skills/.experimental/ivan-bazi-architect`

## Boundary

This skill is for reflective strategy support with citations and uncertainty notes. It is not a deterministic guarantee engine.

## Contributor Notes

- Keep personal absolute paths out of committed files.
- Store local source directories in uncommitted `config.json`.
- Add new failure patterns to `references/gotchas.md` when you see repeat model mistakes.
42 changes: 42 additions & 0 deletions skills/.experimental/ivan-bazi-architect/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
---
name: ivan-bazi-architect
description: Use when users explicitly ask for 八字/命理 style analysis, SW-1/SW-2/SW-3 structured diagnosis, or citation-backed summaries from classical BaZi references. Do not trigger for general scientific, legal, medical, or deterministic certainty requests.
---

# Ivan Bazi Architect

Convert classical BaZi references into a structured, auditable decision workflow.

## Workflow

1. Load source knowledge and setup.
- Use `references/core-books.md` to map canonical books and filename variants.
- Use `config.example.json` as the setup template (`source_dir`, output preferences).
- Prefer a local, user-managed `config.json` that is not committed.
2. Build or refresh index.
- Run `scripts/build_pdf_index.py` to extract searchable PDF metadata and snippets.
- CLI argument `--source-dir` overrides config.
- Keep output under local skill workspace (do not overwrite source PDFs).
3. Run layered diagnosis.
- SW-1 (调候层): identify first-priority environmental resource.
- SW-2 (格局层): identify dominant system logic and flow chain.
- SW-3 (反馈层): run conflict/combination stress checks.
4. Trigger circuit-breaker rules.
- Detect high-risk 用神受损 scenarios.
- Emit warning tier and fallback options.
5. Publish output with boundaries.
- Provide concise recommendations with references and confidence levels.
- Keep ethical boundary: advisory for reflection/decision support, not deterministic fate claims.
6. Apply gotchas checks before final answer.
- Use `references/gotchas.md` to avoid overclaiming, weak citations, and unsupported certainty language.

## Output Contract

Return in this structure:

1. Input summary (what data was analyzed).
2. SW-1 / SW-2 / SW-3 findings.
3. Circuit-breaker alerts (if any).
4. Recommended actions (primary + fallback).
5. Source citations (book + section snippet).
6. Boundary note (scope, uncertainty, ethical limits).
4 changes: 4 additions & 0 deletions skills/.experimental/ivan-bazi-architect/agents/openai.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
interface:
display_name: "Ivan Bazi Architect"
short_description: "Structured BaZi diagnosis with citations, uncertainty notes, and guardrails."
default_prompt: "Use Ivan Bazi Architect when the user explicitly asks for BaZi-style analysis. Build or reuse an index from configured PDFs, run SW-1/SW-2/SW-3 diagnosis, and produce a cited, bounded strategy brief."
5 changes: 5 additions & 0 deletions skills/.experimental/ivan-bazi-architect/config.example.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"source_dir": "/path/to/your/bazi-pdfs",
"output_format": "audit_memo",
"citation_mode": "book_file_snippet"
}
26 changes: 26 additions & 0 deletions skills/.experimental/ivan-bazi-architect/references/core-books.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# Core Books Map

Source path:

- Read from `config.json` (`source_dir`) or pass `--source-dir` to the index script.
- Keep user-specific local paths out of committed files.

Use keyword matching because filenames may include suffixes like `(Z-Library)`, `_compressed`, uppercase `.PDF`, or author notes.

## Canonical Mapping

1. 三命通会
- Match keywords: `三命通会`
2. 穷通宝鉴
- Match keywords: `穷通宝鉴`
3. 滴天髓 / 子平真诠
- Match keywords: `滴天髓`, `子平真詮`, `子平真诠`
4. 八字提要(韦千里)
- Match keywords: `八字提要`, `韦千里`
5. 周易译注
- Match keywords: `周易译注`

## Suggested Citation Format

- `书名 / 文件名 / 页码(若可得) / 摘录`
- Keep excerpt short and directly relevant to the claim.
24 changes: 24 additions & 0 deletions skills/.experimental/ivan-bazi-architect/references/gotchas.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Gotchas

## Trigger Boundaries

- Use this skill only for explicit BaZi/命理 requests.
- Do not auto-apply to generic life advice, medical, legal, or financial planning prompts.

## Citation Quality

- Every core claim should include at least one citation from indexed sources.
- Do not cite books that are not present in the current index.
- Keep excerpts short and claim-linked.

## Uncertainty and Language

- Do not present outputs as deterministic fate or guaranteed outcomes.
- Prefer confidence ranges and scenario language over absolute predictions.
- Always include a boundary note in the final output.

## Failure Patterns to Avoid

- Skipping SW-1 and jumping directly to pattern labeling.
- Mixing incompatible flow logic without explaining conflict.
- Providing mitigation without a monitoring signal or fallback path.
32 changes: 32 additions & 0 deletions skills/.experimental/ivan-bazi-architect/references/workflow.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# Diagnostic Workflow (SW-1 / SW-2 / SW-3)

## SW-1 调候层

- Determine first-priority environmental resource constraints.
- Prioritize survival/stability conditions before optimization.

## SW-2 格局层

- Identify dominant logic and viable flow chain.
- Reject high-level claims that break the actual flow path.

## SW-3 反馈层

- Evaluate冲/合/克/害 interactions as stress signals.
- Produce risk tier and fallback plan when critical links are damaged.

## Circuit Breaker Rules

- Trigger L4 warning when 用神 support is significantly degraded.
- Always output:
- primary mitigation
- fallback mitigation
- monitoring signal to revisit the decision

## Publishing Style

- Output should be concise, structured, and citation-backed.
- Adapt format to:
- short X post thread
- knowledge-community digest
- executive memo
142 changes: 142 additions & 0 deletions skills/.experimental/ivan-bazi-architect/scripts/build_pdf_index.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
#!/usr/bin/env python3
"""
Build a lightweight JSONL index from BaZi reference PDFs.

Example:
python3 scripts/build_pdf_index.py \
--source-dir "/path/to/your/bazi-pdfs" \
--out references/pdf-index.jsonl

Or use local config fallback:
python3 scripts/build_pdf_index.py \
--config config.json \
--out references/pdf-index.jsonl
"""

from __future__ import annotations

import argparse
import json
from pathlib import Path
from typing import Iterable


KEYWORDS = {
"三命通会": ["三命通会"],
"穷通宝鉴": ["穷通宝鉴"],
"滴天髓_子平真诠": ["滴天髓", "子平真詮", "子平真诠"],
"八字提要": ["八字提要", "韦千里"],
"周易译注": ["周易译注"],
}


def iter_pdfs(source_dir: Path) -> Iterable[Path]:
for p in sorted(source_dir.iterdir()):
if p.is_file() and p.suffix.lower() == ".pdf":
yield p


def detect_tags(file_name: str) -> list[str]:
tags: list[str] = []
for canonical, kws in KEYWORDS.items():
if any(kw in file_name for kw in kws):
tags.append(canonical)
return tags


def read_pdf_sample(pdf_path: Path, max_pages: int, max_chars: int) -> tuple[int, str]:
try:
from pypdf import PdfReader
except Exception as exc: # pragma: no cover
raise RuntimeError(
"pypdf is required. Install with: python3 -m pip install pypdf"
) from exc

reader = PdfReader(str(pdf_path))
text_parts: list[str] = []
page_total = len(reader.pages)
limit = min(max_pages, page_total)
for i in range(limit):
txt = reader.pages[i].extract_text() or ""
if txt:
text_parts.append(txt.strip())
sample = "\n".join(text_parts).strip()
if len(sample) > max_chars:
sample = sample[:max_chars]
return page_total, sample


def read_source_dir_from_config(config_path: Path) -> str:
raw = config_path.read_text(encoding="utf-8")
data = json.loads(raw)
source_dir = data.get("source_dir")
if not isinstance(source_dir, str) or not source_dir.strip():
raise RuntimeError(f"config missing non-empty string field 'source_dir': {config_path}")
return source_dir


def main() -> int:
parser = argparse.ArgumentParser(description="Build PDF metadata index JSONL")
parser.add_argument("--source-dir", help="Directory with source PDFs")
parser.add_argument(
"--config",
default="config.json",
help="Config JSON path with source_dir fallback (default: config.json)",
)
parser.add_argument(
"--out",
default="references/pdf-index.jsonl",
help="Output JSONL path (default: references/pdf-index.jsonl)",
)
parser.add_argument("--max-pages", type=int, default=6, help="Pages to sample per file")
parser.add_argument("--max-chars", type=int, default=6000, help="Max chars per sample")
args = parser.parse_args()

source_dir_raw = args.source_dir
if not source_dir_raw:
config_path = Path(args.config).expanduser().resolve()
if not config_path.exists():
raise SystemExit(
f"Missing source dir. Pass --source-dir or provide config file: {config_path}"
)
try:
source_dir_raw = read_source_dir_from_config(config_path)
except Exception as exc:
raise SystemExit(f"Failed to read source_dir from config: {exc}") from exc

source_dir = Path(source_dir_raw).expanduser().resolve()
out_path = Path(args.out).resolve()
out_path.parent.mkdir(parents=True, exist_ok=True)

if not source_dir.exists() or not source_dir.is_dir():
raise SystemExit(f"Source directory does not exist: {source_dir}")

indexed = 0
with out_path.open("w", encoding="utf-8") as fout:
for pdf in iter_pdfs(source_dir):
page_count, sample = read_pdf_sample(pdf, args.max_pages, args.max_chars)
row = {
"file_name": pdf.name,
"file_path": str(pdf),
"page_count": page_count,
"tags": detect_tags(pdf.name),
"sample_text": sample,
}
fout.write(json.dumps(row, ensure_ascii=False) + "\n")
indexed += 1

summary_path = out_path.with_suffix(".summary.json")
summary = {
"source_dir": str(source_dir),
"indexed_files": indexed,
"index_path": str(out_path),
}
summary_path.write_text(json.dumps(summary, ensure_ascii=False, indent=2), encoding="utf-8")

print(f"Indexed {indexed} PDFs -> {out_path}")
print(f"Summary -> {summary_path}")
return 0


if __name__ == "__main__":
raise SystemExit(main())