Skip to content

Latest commit

 

History

History
400 lines (318 loc) · 20.9 KB

File metadata and controls

400 lines (318 loc) · 20.9 KB

mind-forge

A local-first, AI-native CLI for card-based writing.

mf treats your knowledge base as a codebase. Articles are assembled from composable Blocks, every piece of state lives in plain files on disk, and the CLI is shaped so both humans and Agents can drive it.

Philosophy

Three ideas guide every decision in mf:

Diffusion

Knowledge is meant to spread. Capture it once as a Block, then let it diffuse — through articles, glossary terms, builds, and downstream publishers like Yuque or static sites. The same atomic unit can land in a report today and a paper tomorrow, without copy-paste drift.

flowchart LR
  subgraph Capture
    B((Block))
    S[Source]
    T[Term]
  end
  subgraph Compose
    A1[Article: Report]
    A2[Article: Paper]
  end
  subgraph Ship
    P1[Publisher: Yuque]
    P2[Publisher: Local]
  end
  B --> A1
  B --> A2
  S --> A1
  T --> A2
  A1 --> P1
  A1 --> P2
Loading

DaC — Document as Code

Your writing follows the same discipline as your infrastructure:

declarative YAML configs (minds.yaml, mind.yaml, mind-index.yaml), schema validation, deterministic builds, and full git auditability. If you can review a PR, you can review a chapter.

AI Native CLI

mf is designed first for AI Agents, not for human terminal sessions. Every command speaks a JSON envelope ({ status, command, data }), exits with stable codes, and produces deterministic output contracts. Build a pipeline with shell, Make, or an LLM — the contract is the same.

This is an independent philosophy, not a subset of DaC: AI Native CLI rejects interactive prompts, colored output designed for human eyes, and inconsistent exit codes. The tool is a reliable API for an LLM to call.

Local-first underpins all three: no cloud, no lock-in, plain markdown and YAML you can edit in any editor.

Install

Requires Rust 1.75+.

git clone https://github.com/alswl/mind-forge.git
cd mind-forge
cargo install --path .

Or run from source while iterating:

cargo run -- --help

Shell completion:

mf completion zsh   # or bash | fish | powershell | elvish

Quick Start

# 1. Create a Mind Repo
mkdir my-repo && cd my-repo
mf init                                # creates minds.yaml + projects/

# 2. Create a project (path-based identity, Unicode/emoji/dates supported)
mf project new blog
mf project new workspaces/team/projects/2026-W21

# 3. Create an article
mf article new "First Post" --project blog

# 4. Add sources, assets, and terms
mf source new https://example.com/ref --file-kind web --project blog
mf asset new diagram.png --project blog
mf term new "Zettelkasten" --definition "A note-taking method" --project blog

# 5. Index, build, and publish
mf article index --project blog
mf build "First Post" --project blog
mf publish run "First Post" --target local --project blog

Manual

See docs/manual.md for the full user manual, including repo layout, shared CLI contracts, scripting patterns, and end-to-end workflows for projects, articles, sources, assets, terms, builds, publishing, templates, and configuration.

Core Concepts

Concept What it is
Mind Repo A directory rooted at minds.yaml. The outermost unit of organization.
Project A subdirectory with mind.yaml. Default layout: docs/, sources/, assets/, outputs/.
Article A document — either a single Markdown file or a directory of ordered files.
Block An atomic, reusable unit of content composed into articles.
Source An external reference (web page, PDF, RSS feed, file) tracked per project.
Asset A binary or non-text resource attached to a project.
Index mind-index.yaml per project — the source of truth for everything above.
Publisher A target (e.g. local, yuque-prompt) that ships built output somewhere.

All on-disk YAML follows the mind 0.3.0 format (schema: "1"), so repos move freely between mf and other mind-compatible tools.

How the pieces fit on disk:

flowchart TD
  Repo[Mind Repo<br/><code>minds.yaml</code>]
  Repo --> P1[Project: blog<br/><code>mind.yaml</code>]
  Repo --> P2[Project: papers<br/><code>mind.yaml</code>]
  P1 --> Docs[docs/]
  P1 --> Sources[sources/]
  P1 --> Assets[assets/]
  P1 --> Outputs[outputs/]
  P1 --> Idx[<code>mind-index.yaml</code>]
  Docs --> A1[essay.md<br/>file article]
  Docs --> A2[2026-review/<br/>directory article]
  A2 --> A2a[01-intro.md]
  A2 --> A2b[02-details.md]
Loading

Workflow

A typical loop:

flowchart LR
  C[Capture<br/><code>mf source</code><br/><code>mf asset</code><br/><code>mf term</code>]
  D[Draft<br/><code>mf article new</code>]
  I[Index<br/><code>mf … index</code><br/><code>mf project lint --fix</code>]
  B[Build<br/><code>mf build</code>]
  P[Publish<br/><code>mf publish run</code>]
  C --> D --> I --> B --> P
  P -. new insights .-> C
Loading
  1. Capturemf source new and mf asset new pull raw material into a project. mf term new records vocabulary.
  2. Draftmf article new <TYPE> <TITLE> [--template <S>] [--file] scaffolds a directory article (default) or single file (--file) under docs/. The default template is blank; --template arch|prd|blog selects another built-in scaffold, and --template <path> reads a project-local Markdown template. New articles automatically get Typora front matter (typora-copy-images-to) pointing to the project assets directory (disable with plugins.typora-front-matter.enabled: false in mind.yaml). Edit in any Markdown editor.
  3. Indexmf source index, mf article index, and mf project lint --fix reconcile mind-index.yaml with the filesystem.
  4. Buildmf build <article> assembles output (directory articles merge their files in filename order) into outputs/<article>.md.
  5. Shipmf publish run … --target <publisher> pushes to a configured target.

Every step is idempotent and pipe-friendly. Pass --json to any command to get a machine-readable envelope.

Command Reference

Flags

These flags are available on most commands:

Flag Description
--root <PATH> Mind Repo root directory
--config <PATH> Config file path
-p, --project <PROJECT> Project selector for project-scoped commands
-v, --verbose... Verbose output (repeatable)
-q, --quiet Silence non-error output
-o, --output <text|json> Output format (default: text)
--json Shorthand for --output json
--no-color Disable colored output
-h, --help Show help
-V, --version Show version

Shared flag families (uniform across all commands they apply to):

Flag family Applies to Description
--dry-run every mutating command (new, rename, remove, archive, update, index, lint --fix) Preview without writing
-f, --force every new/rename/remove/archive Proceed despite safety checks: overwrite an existing target, or remove an entity referenced by others
-y, --yes every remove and archive Confirm destructive action non-interactively
--no-headers, --no-trunc every list Suppress table header / disable column truncation
--fix, --rule <RULE>, --severity <LEVEL>, --max-warnings <N> every lint Auto-fix, restrict rule, filter severity, fail on warnings > N

--project is available on project-scoped commands (article, asset, source, term, build, publish run, etc.) and accepts repo-relative paths or project names. When running inside a project directory, --project can be omitted — the CLI auto-detects the current project. When run outside a project directory without --project, mf article list automatically matches all projects and sorts articles by most recently modified.

mf init [PATH] — Initialize a Mind Repo

Bootstrap a directory as a Mind Repo (creates minds.yaml and the default projects/ container). Defaults to the current directory.

mf project — Manage projects

Subcommand Description
new <PATH> Create a project. Accepts cwd-relative or repo-relative paths with Unicode, emoji, dates, spaces. --template <TEMPLATE>
list (ls) List projects
show <PATH> Show project details
update <PATH> Update project metadata. --description <TEXT>, --clear-description
rename <OLD_PATH> <NEW_PATH> Rename a project
remove <PATH> (rm) Remove a project (interactive confirmation in TTY)
archive <NAME_OR_PATH> Archive a project to _archived/ (interactive confirmation in TTY)
lint Lint project(s). Rules: missing_directory, stale_index_entry, name_convention, missing_manifest, duplicate_key. Requires -p, --project <PROJECT>
index Index projects (mf extension)
import <DIRECTORY> Import a directory as a project. --type <TYPE>, --source <DIR>, --assets <DIR>, -y, --yes

mf article — Manage articles

Subcommand Description
new <TITLE> Create an article. -t, --template blank|arch|prd|blog|<path>, --file, --tag <TAG>, --draft
list (ls) List articles. Omitting --project outside a project dir lists all articles across all projects, sorted by most recently modified.
show <PATH> Show article details
update <PATH> Update article metadata. --status draft|published
rename <OLD_PATH> <NEW_PATH> Rename an article
remove <PATH> (rm) Remove an article (interactive confirmation in TTY)
lint Lint articles
convert Convert article shape between directory and single-file. --to-single-file, --to-directory, --dry-run
index Index articles (mf extension). --dry-run previews without writing

mf source — Manage content sources

Subcommand Description
new <INPUT> Add a source. -n, --name <NAME>, --file-kind auto|pdf|file|rss|web, --source-kind yuque|meeting|misc, --link
list (ls) List sources. --filter <PATTERN>, -t, --type <KIND>
show <PATH> Show source details
update <PATH> Update a source (mf extension). --url <URL>, --rename <NAME>
rename <OLD_PATH> <NEW_PATH> Rename a source
remove <NAME_OR_PATH> (rm) Remove a source. --keep-file
index Index sources (mf extension)
clean Clean stale index entries

mf asset — Manage project assets

Subcommand Description
new <PATH> Add an asset. --name <NAME>, --tag <TAG>, --copy/--link
list (ls) List assets. --filter <PATTERN>, --type image|video|audio|other
show <PATH> Show asset details
update [PATH] Update assets. --set-url <URL>, --channel <CHANNEL>, --all
rename <OLD_PATH> <NEW_PATH> Rename an asset
remove <PATH> (rm) Remove an asset
index Index assets (mf extension). --refresh-metadata
clean Clean stale index entries

mf term (alias: mf terms) — Manage terminology

Subcommand Description
new <TERM> Create a term (mf extension). --definition <TEXT>, --description <TEXT>, --confidence <N>, --alias <TEXT>, --tag <TAG>, --misrecognition <TEXT>
list (ls) List terms. --filter <PATTERN> matches term name (substring); --tag <TAG> / --alias <ALIAS> match their respective fields. --has-correction, --scope project|global|all (AND semantics; default merges project + global fallback)
show <TERM> Show term details
update <TERM> Update term metadata and corrections. --definition <TEXT>, --description <TEXT>, --confidence <N>, --alias <TEXT>, --tag <TAG>, --clear-description, --clear-confidence, --delete-alias <TEXT>, --delete-tag <TAG>, --add-correction <ORIGINAL> (repeatable), --correction-match <ORIGINAL:KIND>, --correction-fix <ORIGINAL:KIND>, --correction-pinyin <ORIGINAL:PINYIN>, --delete-correction <ORIGINAL> (repeatable), --dry-run
correction <SUBCOMMAND> Manage corrections as a first-class subresource: add <TERM> <ORIGINAL> <CORRECT> (idempotent; reports created: true|false; --match, --fix, --boundary, --pinyin), list <TERM>, show <TERM> <ORIGINAL>, update <TERM> <ORIGINAL>, remove <TERM> <ORIGINAL> (--dry-run)
move <TERM> (mv) Move a term between scopes. --to-global, --to-project <PROJECT>, --from-global, --force (overwrite destination; source preserved on rejection), --dry-run
rename <OLD_TERM> <NEW_TERM> Rename a term. --keep-alias keeps the old name as an alias
remove <TERM> (rm) Remove a term (interactive confirmation in TTY)
lint [PATH] Lint term consistency in project docs. CJK matching uses jieba word segmentation (word default — both edges must align with token boundaries); substring bypasses jieba; pinyin for tone-less scan. --fix, --term <NAME> (repeatable), --include-suggested, --article <SLUG> or a Markdown PATH to target a single article/file. Non-TTY --fix exits 2 without -y/--yes.
fix [PATH] First-class alias for term lint --fix. Same flags as lint + --include-suggested for suggested corrections. Accepts repeatable --term <NAME> to scope to one or more terms (case-sensitive exact canonical match; unknown → exit 2).

Global terms (created without --project) are stored in minds-terms.yaml at the repo root. Project-scoped terms live in each project's mind-index.yaml.

Corrections follow two paths. mf term lint/fix deterministically applies the declared glossary corrections — the closed-set, recurring domain terms — to project docs under guardrails (no edit inside a protected term occurrence, declared-correction precedence, non-overlapping edits, atomic write after diff/confirm). Open-domain ASR errors that no fixed list can enumerate are corrected by the driving agent, then persisted via mf term correction add once they recur. mf owns the deterministic guardrails; the agent owns the open-domain judgment.

mf build <ARTICLE> — Build articles

-o, --output <PATH>, --dry-run. ARTICLE may be an indexed name/slug or a repo-relative path prefixed with @ (e.g. @projects/blog/docs/2026-03-review/). Directory articles are built by merging Markdown files in filename order. Relative image/link/reference paths are automatically rewritten to resolve from the output directory; paths inside fenced code blocks, absolute paths, and URLs are left unchanged.

mf publish — Publish articles & manage targets

Subcommand Description
run <ARTICLE> Publish to a target (supported: local, yuque-prompt). --target <TARGET> (optional when publish.default_target is configured). File-based publishers discovered for both explicit and default targets. Local publishers honor config.prefix.
update <ARTICLE> Update a publish record. --target <TARGET> (required), --status draft|published|archived, --target-url <URL>, --set <KEY=VALUE>
target list List publish targets and diagnostics
target show <NAME> Show publish target details

mf render template — Render templates

Subcommand Description
list List built-in and project-local render templates
show <NAME> Show template details + preview

mf config — Manage configuration

Subcommand Description
schema Show config JSON schema. --output-format json|yaml (default: json)
show Show effective config (canonical JSON envelope). --output-format json|yaml (default: yaml)
generate Generate effective config file. --output-format json|yaml (default: yaml), -o, --output <PATH>
default Show default config values. --output-format json|yaml (default: yaml)
terminal Show terminal capability diagnostics (hyperlink support, color depth, terminfo probing). Respects TERM, COLORTERM, TERM_PROGRAM, NO_COLOR, MF_FORCE_HYPERLINKS, MF_NO_HYPERLINKS.

mf completion <SHELL> — Generate shell completion

Supported shells: bash, zsh, fish, powershell, elvish

mf version — Show version information

Text output includes commit / build_date / rustc. JSON envelope adds target_triple. Pass --json for the machine-readable form.

Features

  • Repo bootstrapmf init [PATH] creates minds.yaml and .mind/
  • Project lifecyclemf project new | list | show | update | rename | remove | archive | lint | index | import; path-based identity supports Unicode, emoji, dates, spaces
  • Project auto-detection — running inside a project directory auto-injects --project; mf article list without --project outside a project dir auto-matches all projects, sorted by most recently modified; cwd-relative paths normalized to repo-relative canonical identity
  • Article managementmf article new | list | show | update | rename | remove | lint | index; directory articles by default, --file for single-file shape; --template blank|arch|prd|blog or custom project-local template path
  • Sourcesmf source new | list | show | update | rename | remove | index | clean; --file-kind auto|pdf|file|rss|web, --source-kind yuque|meeting|misc
  • Assetsmf asset new | list | show | update | rename | remove | index | clean; --copy/--link for copy vs symlink
  • Glossarymf term new | list | show | update | correction | move | rename | remove | lint; global terms in minds-terms.yaml, project-scoped in mind-index.yaml
  • Build — config-driven assembly, directory-article merging, --dry-run, --output, and @path/-style article addressing
  • Publishmf publish run | update | target list | target show against per-target publishers (local, yuque-prompt); project-level local targets resolve relative paths from project root
  • Render templatesmf render template list | show covers built-in and project-local templates
  • Configmf config schema | show | generate | default; centralized defaults for docs/, sources/, assets/, _archived/, and outputs/
  • Pluginsmind.yaml supports a plugins block for forward-compatible plugin configuration; the typora-front-matter plugin is enabled by default and injects typora-copy-images-to front matter into new articles
  • Compatibility — reads and writes mind 0.3.0 YAML; tolerates older schema_version and list-based shapes on read
  • Shell completionmf completion <SHELL> for bash, zsh, fish, powershell, elvish
  • Versionmf version includes commit / build_date / rustc / target_triple
  • Terminal intelligencemf config terminal for capability diagnostics; automatic OSC 8 hyperlink rendering in list/show/verb outputs when supported; broad terminal emulator detection (iTerm2, Ghostty, Kitty, VS Code, Warp, Terminal.app, tmux, WezTerm, etc.) plus MF_FORCE_HYPERLINKS/MF_NO_HYPERLINKS overrides; file:// URI encoding for paths with spaces or Unicode
  • Output contractstext by default, --json for { status, command, data } envelopes; canonical per-verb shapes; identity round-trip between list and show; remove/archive use a TTY confirmation protocol; stable exit codes

Output Contracts

Every mf command adheres to shared text-layout and JSON-envelope contracts. These are documented in the feature specification:

Contract Description
List layout Unified table format for all mf <noun> list commands
Show layout Unified key-value block format for all mf <noun> show commands
Verb envelopes Per-verb JSON shapes (create, rename, remove, update, index, lint)
Flag conventions Required flags every command must accept
Confirmation protocol TTY-only interactive prompt for destructive verbs

Key rules:

  • data is always a JSON object — no bare arrays, strings, or null
  • Text output adapts to TTY (headers + ANSI) vs pipe (no headers, no ANSI, same row shape)
  • Every resource carries an identity field that round-trips between list and show
  • --dry-run is available on every mutating command
  • Remove and archive require confirmation in TTY; non-TTY exits 1 without --yes/--force

Project Status

See specs/ for detailed specifications and the feature evolution plan.

License

MIT