Metadata-Version: 2.4
Name: note-state
Version: 0.1.0
Summary: A portable state-tracking layer for markdown note vaults (Obsidian, Dendron, Foam, and plain markdown folders).
Author-email: superxgen <superxgen@gmail.com>
License: MIT
Project-URL: Homepage, https://github.com/resystem0/note-state
Project-URL: Issues, https://github.com/resystem0/note-state/issues
Keywords: notes,markdown,obsidian,pkm,zettelkasten,frontmatter,state-machine
Classifier: Development Status :: 3 - Alpha
Classifier: Environment :: Console
Classifier: Intended Audience :: End Users/Desktop
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Topic :: Text Processing :: Markup :: Markdown
Classifier: Topic :: Utilities
Requires-Python: >=3.9
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: PyYAML>=6.0
Dynamic: license-file

# note-state

A portable "patch" for turning a pile of notes into a *pipeline*: every note
carries an explicit `state` telling you how far it's traveled from raw
capture to integrated, trustworthy knowledge — the same way a ticket in an
issue tracker carries a status, or a part on an assembly line carries a
stage.

Works with any note application that stores notes as markdown files with
**YAML frontmatter** on local disk — Obsidian, Dendron, Foam, Logseq, plain
markdown vaults, even a folder of `.md` files with no app at all.

## Install

```bash
pip install note-state
```

## The pipeline

```
drafting → review → formatting → referencing → integrating → published
                ↘         ↘            ↘             ↘
                          needs_revision  (loops back to whichever
                                           stage flagged the problem)

              any state ──────────────────────────────→ archived
```

| State | What happens here | Exit condition |
|---|---|---|
| **Drafting** | Raw capture. Get the idea down with as little friction as possible. | The idea has enough substance to be judged. |
| **Review** | Read it critically: accurate, internally consistent, complete? | Content is verified, or it's sent back to Drafting. |
| **Formatting** | Give it shape: headings, atomic scope, a real title, clean prose, tags. | It reads well and is scoped correctly. |
| **Referencing** | Attach provenance: citations, source links, backlinks. | Every non-obvious claim is traceable to a source. |
| **Integrating** | Weave it into the graph: link from a Map of Content, cross-link related notes. | It's reachable from at least one other place in the vault. |
| **Published** | Stable and reusable — safe to cite, export, or share. | Terminal, but can be pulled back into Integrating. |
| **Needs Revision** *(utility state)* | Something's wrong. Flagged from any stage. | Always exits back to the stage that flagged it. |
| **Archived** *(utility state)* | Retired or superseded. | Terminal. |

This isn't sacred — it's just the bundled default. Drop your own
`states.yaml` next to your notes (or in any parent directory) to define a
different pipeline; `note-state` doesn't hardcode the states, it just
enforces whatever pipeline you describe.

## The metadata schema

Every tracked note gets two frontmatter fields: the current state, and a
timestamped log of how it got there.

```yaml
---
title: "Maps of Content connect clusters of related notes"
state: referencing
state_history:
  - state: drafting
    date: 2026-07-01
  - state: review
    date: 2026-07-05
  - state: formatting
    date: 2026-07-08
  - state: referencing
    date: 2026-07-12
    note: "added three sources"
tags: [pkm, moc]
---

Note body goes here as normal — nothing about the state system touches
the content itself.
```

`state_history` is what makes the system useful beyond a label: it's an
audit trail you can query later ("which notes have been stuck in Review for
three weeks?", "how long does formatting usually take?").

## Usage

```bash
# Stamp every note in a folder with the initial state (only touches
# notes that don't already have one — safe to run repeatedly)
note-state init ./my-vault

# Move a note forward
note-state set my-vault/atomic-notes.md review

# Try to skip a stage — this is rejected unless you pass --force
note-state set my-vault/atomic-notes.md published

# See what's where
note-state list ./my-vault
note-state list ./my-vault --state review

# Find bottlenecks — counts per state + oldest untouched notes
note-state report ./my-vault

# Print the pipeline as a Mermaid diagram (paste into anything that renders it)
note-state graph
```

## Customizing the pipeline

Two files define the state machine:

- **`states.yaml`** — states + allowed transitions. `note-state` looks for
  this file (or `.note-states.yaml`) in the current directory, then any
  parent directory, and falls back to the bundled default pipeline above if
  none is found. Copy the bundled default as a starting point and edit
  freely — rename stages, add a `translating` or `peer-review` state,
  rewire transitions.
- Pass `--config path/to/states.yaml` to point at a specific file instead
  of relying on directory discovery.

## Wiring it into a specific app

- **Obsidian, Dendron, Foam, plain markdown folders** — these already read
  and preserve YAML frontmatter, so `note-state` works with zero
  adaptation: run it straight against your vault folder. In Obsidian, the
  [Dataview](https://github.com/blacksmithgu/obsidian-dataview) plugin can
  turn `state` into a live board, e.g.:

  ```
  TABLE state, state_history[-1].date AS "last moved"
  FROM "Notes"
  SORT state
  ```

- **Logseq** — pages are markdown files too, but Logseq's own metadata
  lives as a `key:: value` line on the first block rather than a `---`
  frontmatter block. Keep frontmatter *and* Logseq properties side by side
  (Logseq ignores the frontmatter block, `note-state` ignores the `::`
  line), or adapt the parser in `note_state/cli.py` to read
  `state:: drafting` instead.

- **Notion** (or any database-backed app without local files) — recreate
  `states.yaml` as a **Status** property with matching options, and use a
  Board view grouped by it. You lose `note-state`'s enforcement of
  transition rules unless you script it against the Notion API, but the
  state vocabulary and pipeline shape carry over directly.

## Design notes

- **Backward moves are allowed on purpose.** Review can send a note back to
  Drafting; Formatting can send it back to Review. Knowledge work isn't
  strictly linear, and a state system that can't represent "this needs
  another pass" will just get ignored.
- **`needs_revision` is a trapdoor, not a stage.** It exists so a problem
  found at any point can be flagged without losing the note's place in the
  pipeline — it always returns to wherever it came from.
- **`--force` exists deliberately.** Rules are useful defaults, not a cage;
  sometimes you really do want to fast-track or bulk-correct a note.

## License

MIT
