GotSaeng OS

by GotSaeng OS contributors
5
4
3
2
1
Score: 51/100

Description

Local-first Markdown context compiler for Obsidian and AI workflows — auditable, with no cloud, telemetry, or LLM calls.

Reviews

No reviews yet.

Stats

0
stars
115
downloads
1
forks
67
days
1
days
3
days
8
total PRs
0
open PRs
0
closed PRs
8
merged PRs
25
total issues
0
open issues
25
closed issues
33
commits

Latest Version

4 days ago

Changelog

  • Fix: the Obsidian adapter's Report Hub settings tab and output-folder cleanup had four related bugs, all found during an /impeccable critique of apps/obsidian-plugin (public repo issues #21, #22, #25, #26):

    • Routine output-folder cleanup (every Compile/Weekly Review/LLM Handoff/Validate command) only ever considered the two built-in folder names as sweep candidates, regardless of whether this plugin instance had ever actually used them. A file reappearing in an unused built-in folder (e.g. from a vault sync or backup restore) was silently deleted on the next compile. Cleanup now sweeps only folders in a persisted managedOutputFolders set, populated as the user actually consents to output-folder changes.
    • Output-folder cleanup could delete empty ancestor directories above the managed output folder (walking up toward the vault root) even when the plugin did not create them. It now only ever removes the exact managed folder itself.
    • The custom-path text field's blur-commit and the visibility dropdown's change handler could race on a fast user gesture, opening two confirm modals for one logical change and reading settings before either had settled. Output-folder mutations are now serialized.
    • Selecting "Custom path" in the settings dropdown no longer eagerly persists outputFolderVisibility: "custom" before an actual custom folder is committed; declining the subsequent confirm modal now cleanly reverts instead of leaving a mismatched custom + built-in-folder state. The path field is now focused only on the transition into custom mode (not on every settings-tab re-render), and the validation banner refreshes immediately after a successful commit instead of waiting for the tab to be reopened.
    • (Codex review follow-up) A data.json predating managedOutputFolders grandfathered the hidden folder into that set regardless of which folder the vault actually used, reopening the same silent-deletion risk the field was added to close. Legacy settings now start from an empty managed set, plus only the folder actually in use. Serializing racing blur/dropdown calls also still let a fast gesture open two sequential confirm modals (the blur commit's, then the dropdown's, against whatever the first one left behind) instead of one; a generation counter now cancels a superseded queued call outright so only the most current intent ever prompts.
  • Security: writeText/mkdir in every node:fs-backed FileSystemAdapter (packages/cli, packages/mcp, and the corresponding test helpers) now delete a pre-existing symlink at the target path before creating a real file/directory there, instead of writing through it. fs.writeFile follows a symlink at its final path segment; a vault (or CLI output directory) that already had a symlink planted at a generated artifact's predictable name (e.g. .gotsaeng/context-pack/PROJECT_CONTEXT.md) would have that symlink's target truncated and overwritten by a compile, corrupting whatever file or directory it pointed to outside the vault. writeText gates the removal on lstat (not a plain existence check, and not an unconditional remove): lstat reports the link itself rather than following it, so it also catches a dangling symlink (target missing) that an exists()-style check would miss and let the write follow anyway — and only removing when the target is actually a symlink preserves the mode/permissions of a normal pre-existing file across an overwrite, instead of losing them to a remove-then-recreate. apps/obsidian-plugin/src/obsidian-file-system.ts's writeText got the equivalent unconditional try/catch-wrapped removal (Obsidian's DataAdapter exposes no lstat equivalent to gate on directly, so mkdir there is unchanged — see its inline comment), but only swallows a confirmed ENOENT from that removal — any other failure (e.g. a symlink sitting in a directory this process can't write to) now aborts the write instead of falling through to adapter.write(), which would still follow whatever the failed removal left in place. None of this protects against a symlinked ancestor directory in the output path, only the leaf artifact path itself; closing that fully would need validating every path segment, a separate, larger pass.

  • Security: .github/workflows/release.yml's quality job now retains the obsidian-plugin-dist artifact for 14 days instead of the 1-day default. The publish job can sit waiting on a required-reviewer approval (see docs/release.md's "Optional: require manual approval before publish") for as long as the approver takes; a 1-day retention could expire the artifact mid-wait, so github-release would fail to download it after publish already published the (now immutable) npm packages, leaving the release stuck with no clean way to finish just the GitHub Release step.

  • Security: .github/workflows/release.yml's github-release job no longer runs pnpm install/pnpm build itself while holding a contents: write token — a compromised dependency's install/build script running in that job could have used the checkout-persisted git credential to push commits or tags. It now downloads the Obsidian plugin build produced under the quality job's read-only token instead. All three jobs' actions/checkout steps now set persist-credentials: false.

  • Security: .github/workflows/release.yml's quality job now refuses to proceed (before installing any dependency or running any script) unless the pushed tag's commit is reachable from origin/main — a tag alone only proves tag-push rights, not that its target was reviewed; without this check, and absent separate tag protection in repo settings, anyone who could push a tag could point a version release at unreviewed history. docs/release.md also documents an optional additional layer: binding the publish job to a GitHub Environment (release) that can be configured with required-reviewer approval.

  • Security: .claude/skills/address-pr-review/SKILL.md now checks out a PR with gh pr checkout <n> instead of git checkout <headRefName>. A fork PR's headRefName is attacker-controlled, not globally unique (can collide with an existing local/origin branch, including main), and can contain shell metacharacters — gh pr checkout resolves the PR by its immutable number via the API instead of building a git command out of that text. Also added an explicit trust caveat, since the skill goes on to run this repo's own package scripts and push a commit.

  • Obsidian adapter: GotSaengSettingTab now implements the declarative settings API (getSettingDefinitions/getControlValue/setControlValue, Obsidian >=1.13.0), so its six settings are searchable in Obsidian's built-in settings search. display() stays as the fallback for hosts older than 1.13.0 — manifest.json's minAppVersion is unchanged (1.5.0). Four settings (project name, stale days, strict validation, open-after-compile) use native control definitions. The other two (output folder visibility, output folder path) use the render escape hatch instead: no control type exposes a blur-only commit or a confirm-before-persist gate, and reproducing either with a native text/dropdown control's per-change setControlValue would fire the 0.12.0 delete-confirmation dialog once per keystroke — exactly the regression that release fixed. Both render definitions share their actual logic with display() via two extracted methods, so nothing is implemented twice. Closes #24.

  • Obsidian adapter: apps/obsidian-plugin/tsconfig.json now includes the DOM lib. Without it HTMLElement and friends resolved to TypeScript's error type, so every createEl, createDiv, and addEventListener call in main.ts and view.ts was silently unchecked — tsc stayed quiet because the error type is assignable to everything. This is what produced the bulk of the "unsafe member access on an any value" findings in the Obsidian community plugin scorecard for the adapter's own source. Types only; no runtime change.

  • Tooling: ESLint now runs typescript-eslint's recommendedTypeChecked rule set over all TypeScript, wired to the real tsconfigs via projectService. The no-unsafe-* rules that the scorecard reports were never active locally, so pnpm lint could not catch what it flagged. pnpm lint still exits 0 at --max-warnings 0.

  • Core: validation messages for type, created, and updated now show the offending frontmatter value as JSON when it is a map or a sequence. They previously ran it through String(), which rendered any object-valued field as an unhelpful [object Object].

  • CLI: the --json payload shapes are now named types (CompileJsonPayload, CliErrorJsonPayload, ValidationJsonPayload) annotated onto the literals packages/cli/src/output.ts emits, so a drift from the documented schema is a type error. This is an internal type-safety change, not a new public API: output.ts is not re-exported from the package entry point. Output is byte-identical.

  • Core: packages/core no longer imports node:fs (or fast-glob, which pulls it in) anywhere. Every read/write goes through a new FileSystemAdapter interface (adapters/file-system.ts) injected by the caller: compileContextPack, writeContextPack, scanSourceFiles/scanMarkdownFiles, parseMarkdownFile, and every exporter now take one as their first argument. packages/cli and packages/mcp each construct a node:fs-backed implementation (node-file-system.ts); apps/obsidian-plugin constructs one backed by app.vault.adapter instead (obsidian-file-system.ts), translating the same absolute, under-vault-root paths core has always used into the vault-relative paths Obsidian's adapter expects. output-cleanup.ts and the three remaining direct-fs call sites in main.ts (output read/write, compile-report read) were converted the same way. Scanning itself moved from fast-glob to an adapter.list()-based recursive walk with micromatch ignore-glob filtering, a known-**-suffix pruning optimization to avoid walking .git/node_modules-sized ignored subtrees, and explicit dotfile exclusion to preserve fast-glob's old dot: false behavior. Closes #22. apps/obsidian-plugin/dist/main.js also aliases fs/node:fs to a throwing stub at build time (tsup.config.ts, scripts/fs-stub.cjs), since gray-matter's index.js does an unconditional (but, for how this plugin calls it, unreachable) top-level require('fs') for its unused matter.read(filePath) overload — the stub is what makes "no node:fs import reachable from the built plugin" true of the bundle as shipped, not just of this repo's own source. Local-only I/O throughout; no behavior change for CLI/MCP users, and Obsidian users get the same compiled output as before.

README file from

Github

GotSaeng OS

GotSaeng OS 生

Compile your scattered Markdown notes into model-ready context packs — local-first, no telemetry, no cloud.

Reclaim your scattered life. 흩어진 생을 다시 손에 쥐다.

npm version CI License: MIT Node >=20 local-first · no telemetry

Quick Start

Requires Node.js 20 or newer. No install needed.

npx -y @gotsaeng/[email protected] compile <vault> --output <dir> --project "<name>"

Both --output and --project are required flags. Copy-paste example using the included sample vault:

npx -y @gotsaeng/[email protected] compile ./examples/sample-vault --output ./out --project "GotSaeng OS"

This writes 15 artifacts to ./out/ including PROJECT_CONTEXT.md, MEMORY_SNAPSHOT.md, DECISION_LOG.md, MEMORY_DIFF.md, COMPILE_REPORT.json, and more.

See it in action

GotSaeng OS terminal demo

See examples/README.md for the full sample vault walkthrough and expected output.

What GotSaeng OS Does

Capability What it does
Vault scanning Recursively scans a local Markdown vault
Note classification Classifies notes into project, decision, research, weekly review, chat export, and template types
Extraction Extracts facts, decisions, actions, risks, assumptions, questions, insights, and stale context
Context pack output Writes auditable Markdown + JSON artifacts with source coverage stats
Memory diff Deterministic local diff comparing previous and current compile manifests
Provenance scoring Scores extracted items from local metadata — a heuristic for triage, not semantic verification
Confidence scoring Scores extraction reliability from deterministic local signals only
Contradiction candidates Surfaces candidate cues for human review — a review queue, not a semantic engine
Obsidian adapter Desktop-only plugin with Report Hub view, hidden output folder, and vault commands
CLI Published as @gotsaeng/cli — no global install required via npx
MCP server @gotsaeng/mcp — stdio server exposing 5 tools to MCP clients, published on npm
  • Scans a local Markdown vault.
  • Parses YAML frontmatter with gray-matter.
  • Classifies notes into project, decision, research, weekly review, chat export, template, and unknown types.
  • Extracts explicit facts, decisions, actions, risks, assumptions, questions, and insights.
  • Extracts plain Obsidian task lists and common section patterns such as Summary, Key Points, Open Questions, Contradictions / Uncertainty, and source metadata.
  • Detects stale context from updated dates and open actions.
  • Writes Markdown and JSON context-pack output with extraction and source coverage stats.
  • Adds a desktop-only Obsidian adapter scaffold that calls the same core compiler.
  • Adds Obsidian commands for context-pack compilation, weekly review context, LLM handoff export, and vault validation.
  • Adds a plugin-specific REPORT_HUB.md with Obsidian wikilinks back to source notes.
  • Adds an Obsidian Report Hub view with command buttons, report shortcuts, latest compile metrics, and a ribbon icon.
  • Lets the Report Hub view preview generated Markdown and JSON output files even when the output folder is hidden from Obsidian's file explorer.
  • Adds an Obsidian setting for hidden, visible, or custom output folder placement.
  • Writes CONTEXT_MANIFEST.json as a local item manifest for deterministic memory diffs.
  • Writes MEMORY_DIFF.md by comparing the previous compile manifest against the current compile.
  • Surfaces newly added, changed, newly stale, and resolved context without calling any AI service.
  • Adds deterministic source provenance scoring for extracted items.
  • Writes SOURCE_PROVENANCE.md with strong/weak provenance items and scoring warnings.
  • Records aggregate provenanceStats in COMPILE_REPORT.json.
  • Writes CONFIDENCE.md with deterministic extraction-confidence scoring and warnings.
  • Records aggregate confidenceStats in COMPILE_REPORT.json.
  • Writes CONTRADICTIONS.md with deterministic contradiction, conflict, and uncertainty candidates for human review.
  • Records aggregate contradictionStats in COMPILE_REPORT.json.
  • Writes ENGINEERING_OPS.md, a release-gate snapshot that collects quality, warning, provenance, confidence, and contradiction summaries in one place.
  • Writes TEAM_MEMORY.md, a team-facing handoff with the current objective, active work, decisions, risks, open questions, and review queues.
  • Groups memory-diff details by source note so changed context is easier to review.
  • Calibrates source provenance scoring into strong, moderate, and weak buckets with a visible calibration version.
  • Adds source-note buttons inside the Obsidian Report Hub preview so generated reports can jump back to original vault notes even when output lives in a hidden folder.
  • Infers the current objective from project notes or high-priority open actions.
  • Groups decisions, risks, and questions by source for faster review.
  • Adds warning triage to Markdown and JSON reports.
  • Produces a cleaner high-signal weekly review surface in the Obsidian adapter.
  • Adds a Backlinks section to the Obsidian Report Hub view: aggregates source-note references across every generated Markdown report (not just the one being previewed; JSON artifacts like CONTEXT_MANIFEST.json and COMPILE_REPORT.json are not scanned), grouped by note and ranked by total reference count.
  • Adds Switch Output Folder to Hidden / Switch Output Folder to Visible commands so the managed output folder can be moved without opening plugin settings.
  • Tags each extracted item with a typed confidenceSource field recording how it was extracted (explicit marker, task list, section pattern, or heading inference), so the explicit-marker register-cap exemption is a type-checked field instead of a string match.
  • Makes the extraction cap (perHeading) and, separately, the export-time register caps (register, insights) configurable via CompileOptions.caps / writeContextPack(fsAdapter, pack, outputDir, caps), defaulting to the same 12/200/120 bounds as before.
  • Splits the Context Pack Files grid's Core Reports group into Core Reports and a Governance subgroup so no group exceeds about 7 items, and adds a filter field above the grid to narrow buttons by name.
  • Gives in-flight command buttons a relabeled, aria-busy state instead of only disabling them, and lets the command-failure banner be dismissed on its own, with an action name and timestamp shown alongside the error.
  • Adds aria-pressed to selected artifact buttons, an accessible title and initial focus to the output-folder confirmation dialog, and role="group"/aria-labelledby on each artifact grid section.

What GotSaeng OS Does Not Do

GotSaeng OS does not include SaaS, cloud sync, auth, payments, vector databases, RAG, LLM API calls, OpenAI/Anthropic/Gemini SDKs, autonomous research, a browser extension, a mobile app, or a rich Obsidian-native management UI.

Autonomous research is a long-term research direction, not a current capability. Provenance, confidence, and contradiction candidate scoring are deterministic metadata heuristics, not semantic fact verification.

Naming

GotSaeng OS has two meanings. First, it references the Korean internet phrase 갓생, sometimes translated as "God Life," meaning an intentional, disciplined, high-agency life. Second, it reinterprets the phrase as Got 生, where means life. In this sense, GotSaeng means reclaiming life: taking back scattered time, thoughts, memory, attention, and execution.

GotSaeng OS is ADHD-aware, not ADHD-limited. It is designed for anyone managing fragmented attention, scattered notes, long-running goals, unfinished tasks, research trails, technical decisions, and execution logs.

Why This Exists

LLMs are useful, but long-running work still loses context. Notes live in one place, chat exports in another, decisions in a third, and execution logs are often forgotten. GotSaeng OS starts with a small, local-first compiler that turns scattered Markdown context into a portable handoff pack for humans and AI tools.

CLI Commands

gotsaeng compile <vaultPath> --output <outputDir> --project <projectName> --stale-days 90
gotsaeng validate <vaultPath>
gotsaeng validate <vaultPath> --strict
gotsaeng doctor

validate defaults to compatibility mode for real Obsidian vaults. Unsupported custom note types such as wiki, source, or reflection, and template date placeholders are reported as warnings. Use --strict when you want canonical GotSaeng OS schema enforcement to fail on those fields.

High-volume Markdown sections may be capped in rendered files with an omission notice. Full totals are still recorded in COMPILE_REPORT.json.

Machine-readable output

Both compile and validate accept --json to print a schema-versioned JSON document on stdout instead of the text summary (errors go to stderr as JSON too):

gotsaeng compile <vaultPath> --output <outputDir> --project <projectName> --json
gotsaeng validate <vaultPath> --json
{
  "schemaVersion": 1,
  "command": "compile",
  "project": "GotSaeng OS",
  "source": "<vaultPath>",
  "output": "<outputDir>",
  "itemCounts": { "facts": 4, "decisions": 2 },
  "report": { "filesScanned": 12, "generatedFiles": ["PROJECT_CONTEXT.md", "..."] }
}

Every compile also writes ARTIFACT_INDEX.json to the output directory alongside the other generated files: a name/byte-size/sha256/description entry for every other generated artifact, so downstream tools can verify file integrity without re-reading full contents.

MCP Server

@gotsaeng/mcp exposes GotSaeng OS as a stdio Model Context Protocol server, so MCP clients (Claude Code, Codex, Cursor) can call validate_vault, compile_context_pack, list_context_artifacts, read_context_artifact, and prepare_ai_handoff as structured tools. The vault and output roots are fixed at launch via CLI flags — tools never accept arbitrary absolute paths.

@gotsaeng/[email protected] is the real npm release and holds the latest dist-tag. A one-time bootstrap placeholder (0.0.1, tagged bootstrap) was published earlier only to set up npm Trusted Publisher; it is not latest and should not be used. See docs/mcp.md for details and for running from source.

npx -y @gotsaeng/[email protected] --vault <vaultPath> --output <outputDir> --project "<projectName>"

Add it to your client's MCP config, for example Claude Code (.mcp.json) or Codex/Cursor's equivalent:

{
  "mcpServers": {
    "gotsaeng": {
      "command": "npx",
      "args": [
        "-y",
        "@gotsaeng/[email protected]",
        "--vault",
        "<vaultPath>",
        "--output",
        "<outputDir>",
        "--project",
        "<projectName>"
      ]
    }
  }
}

Obsidian Adapter

GotSaeng OS includes a desktop-only Obsidian adapter in apps/obsidian-plugin. It is a thin wrapper over packages/core, not a separate compiler.

Build it locally:

pnpm --filter @gotsaeng/obsidian-plugin build

For local manual testing, copy the built files into an Obsidian vault plugin folder:

mkdir -p "/path/to/vault/.obsidian/plugins/gotsaeng-os"
cp apps/obsidian-plugin/dist/main.js \
  apps/obsidian-plugin/dist/manifest.json \
  apps/obsidian-plugin/dist/styles.css \
  "/path/to/vault/.obsidian/plugins/gotsaeng-os/"

Then enable GotSaeng OS in Obsidian community plugin settings. If you instead downloaded a built release from GitHub Releases, see Verifying a Downloaded Release Build to confirm the assets were produced by this repo's release workflow before installing them. The adapter adds commands:

  • Compile Context Pack
  • Generate Weekly Review
  • Export LLM Handoff
  • Validate Vault Schema
  • Open Report Hub
  • Switch Output Folder to Hidden
  • Switch Output Folder to Visible

The default output folder is .gotsaeng/context-pack inside the current vault. That hidden folder keeps generated files out of the normal note tree, but the Report Hub view can preview every output artifact directly. In plugin settings, switch output visibility to Visible vault folder to write generated files under Gotsaeng/Context Pack instead. Generated plugin output is ignored by the core scanner to avoid recursively compiling prior reports.

The adapter also writes REPORT_HUB.md, which is intentionally Obsidian-oriented. It keeps source paths as wikilinks so you can jump from generated context back to the notes that produced it. The weekly review output is intentionally shorter than the full context pack and emphasizes current objective, high-priority actions, top questions, top risks, stale context, and warning triage. The memory diff output is deterministic and local-only. It compares the previous CONTEXT_MANIFEST.json in the output folder with the current compile and reports newly added, changed, newly stale, and resolved context. The source provenance output scores extracted items from local metadata such as updated, note type, tags, source status, item status, and priority. It is meant to triage context quality, not to prove whether a claim is true. The confidence output scores extraction reliability from deterministic local signals such as explicit markers, task-list extraction, section patterns, note type, update metadata, item status, and priority. It does not verify claims semantically. The contradictions output surfaces deterministic candidate cues from explicit markers, headings, and contradiction-related language. It is a review queue, not a semantic contradiction engine. The live Report Hub preview extracts source-note references from Markdown and JSON artifacts and shows vault-note buttons above the preview. This keeps .gotsaeng/context-pack hidden while still making compiled context auditable from inside Obsidian. Below the preview, a Backlinks section aggregates source-note references across every generated report, grouped by note and ranked by total reference count, so you can see which reports cite a given note without opening each one.

Develop from Source

Requires Node.js 20 or newer and pnpm.

pnpm install
pnpm --filter @gotsaeng/cli dev compile ./examples/sample-vault --output ./dist/context-pack --project "GotSaeng OS"

Other dev commands:

pnpm --filter @gotsaeng/cli dev doctor
pnpm --filter @gotsaeng/cli dev validate ./examples/sample-vault
pnpm --filter @gotsaeng/cli dev validate ./examples/sample-vault --strict

Architecture

Markdown Vault
-> Scanner
-> Parser
-> Classifier
-> Extractor
-> Stale Detector
-> Source Provenance Scorer
-> Confidence Scorer
-> Contradiction Candidate Detector
-> Context Compiler
-> Markdown/JSON Exporters
-> Local Manifest + Memory Diff
-> CLI and Obsidian adapter
  • packages/core owns parsing, classification, extraction, stale detection, source provenance, confidence scoring, contradiction candidate detection, compilation, manifest/memory diff, and export logic.
  • packages/cli owns command parsing, console output, exit codes, and user-facing terminal errors.
  • apps/obsidian-plugin owns the desktop-only Obsidian adapter shell and delegates compilation to packages/core.

Product Principles

  • Human-in-the-loop by default.
  • Local-first memory.
  • Context over automation.
  • Reactive before autonomous.
  • Portable life context.
  • Compiler, not chatbot.
  • Framework before plugin.

Sample Vault

examples/sample-vault demonstrates polished public demo notes for GotSaeng OS positioning, architecture decisions, weekly review recovery, chat capture, and LLM context engineering research. The sample includes every core extraction marker:

  • fact
  • decision
  • action
  • todo
  • risk
  • assumption
  • question
  • insight

Roadmap

See ROADMAP.md and docs/plugin-roadmap.md for shipped milestones and what's under consideration next.

Contributing

Use pnpm and Node.js 20 or newer.

pnpm typecheck
pnpm test
pnpm build
pnpm lint

See CONTRIBUTING.md.

Security and Privacy

GotSaeng OS is local-only. It does not include telemetry, hidden network calls, credential collection, API key handling, cloud sync, remote execution, or LLM API calls. Generated output stays local in the output directory you choose.

See SECURITY.md.

License

MIT. See LICENSE.