@gmickel/gno 2.5.1 → 2.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (105) hide show
  1. package/README.md +60 -5
  2. package/assets/skill/README.md +5 -1
  3. package/assets/skill/SKILL.md +75 -1
  4. package/assets/skill/cli-reference.md +123 -0
  5. package/assets/skill/examples.md +30 -0
  6. package/assets/skill/mcp-reference.md +52 -0
  7. package/assets/skill/recipes/capture-and-file.md +6 -0
  8. package/assets/skill/recipes/memory-file-decision.md +6 -0
  9. package/assets/skill/recipes/memory-supersede-fact.md +5 -0
  10. package/assets/skill/recipes/session-evidence-lookup.md +98 -0
  11. package/assets/spa-production.json.gz +0 -0
  12. package/browser-extension/artifacts/{gno-browser-clipper-v2.5.1.zip → gno-browser-clipper-v2.6.0.zip} +0 -0
  13. package/browser-extension/artifacts/gno-browser-clipper-v2.6.0.zip.sha256 +1 -0
  14. package/browser-extension/dist/manifest.json +1 -1
  15. package/package.json +2 -1
  16. package/spec/cli.md +347 -24
  17. package/spec/mcp.md +198 -2
  18. package/spec/output-schemas/capture-receipt.schema.json +3 -0
  19. package/spec/output-schemas/mcp-capture-result.schema.json +3 -0
  20. package/spec/output-schemas/memory-remember.schema.json +8 -2
  21. package/spec/output-schemas/request-status.schema.json +113 -0
  22. package/spec/output-schemas/sessions-automation-run.schema.json +46 -0
  23. package/spec/output-schemas/sessions-discovery.schema.json +38 -0
  24. package/spec/output-schemas/sessions-import-receipt.schema.json +156 -0
  25. package/spec/output-schemas/sessions-status.schema.json +432 -0
  26. package/src/cli/commands/ask.ts +14 -2
  27. package/src/cli/commands/capture.ts +55 -96
  28. package/src/cli/commands/daemon.ts +41 -0
  29. package/src/cli/commands/ls.ts +3 -0
  30. package/src/cli/commands/memory.ts +12 -3
  31. package/src/cli/commands/request-status.ts +59 -0
  32. package/src/cli/commands/reset.ts +39 -5
  33. package/src/cli/commands/sessions.ts +713 -0
  34. package/src/cli/commands/shared.ts +14 -1
  35. package/src/cli/program.ts +388 -1
  36. package/src/cli/session-binding.ts +49 -0
  37. package/src/config/types.ts +8 -0
  38. package/src/core/capture-publish.ts +239 -0
  39. package/src/core/capture-sync.ts +3 -0
  40. package/src/core/memory-remember.ts +233 -122
  41. package/src/core/memory-types.ts +11 -0
  42. package/src/core/network-boundary-inventory.ts +8 -0
  43. package/src/core/request-receipts.ts +671 -0
  44. package/src/index.ts +9 -0
  45. package/src/mcp/context.ts +8 -0
  46. package/src/mcp/http-egress.ts +4 -0
  47. package/src/mcp/http-transport.ts +2 -0
  48. package/src/mcp/tools/capture.ts +87 -83
  49. package/src/mcp/tools/index.ts +66 -0
  50. package/src/mcp/tools/memory-remember.ts +7 -0
  51. package/src/mcp/tools/memory-shared.ts +7 -1
  52. package/src/mcp/tools/request-status.ts +73 -0
  53. package/src/mcp/tools/sessions.ts +208 -0
  54. package/src/sdk/client.ts +180 -84
  55. package/src/sdk/index.ts +6 -0
  56. package/src/sdk/types.ts +54 -2
  57. package/src/serve/capture-service.ts +98 -32
  58. package/src/serve/config-sync.ts +3 -2
  59. package/src/serve/public/app.tsx +4 -1
  60. package/src/serve/public/components/CaptureModal.tsx +26 -8
  61. package/src/serve/public/components/sessions/AutomationPanel.tsx +800 -0
  62. package/src/serve/public/components/sessions/ImportReceipt.tsx +238 -0
  63. package/src/serve/public/components/sessions/SessionSearch.tsx +286 -0
  64. package/src/serve/public/components/sessions/SourcesPanel.tsx +541 -0
  65. package/src/serve/public/components/sessions/api.ts +40 -0
  66. package/src/serve/public/components/sessions/snippet.tsx +53 -0
  67. package/src/serve/public/globals.built.css +1 -1
  68. package/src/serve/public/hooks/use-api.ts +10 -2
  69. package/src/serve/public/lib/request-intent.ts +69 -0
  70. package/src/serve/public/lib/workspace-actions.ts +12 -1
  71. package/src/serve/public/lib/workspace-tabs.ts +2 -0
  72. package/src/serve/public/pages/Dashboard.tsx +10 -0
  73. package/src/serve/public/pages/DocView.tsx +15 -1
  74. package/src/serve/public/pages/DocumentEditor.tsx +139 -96
  75. package/src/serve/public/pages/Sessions.tsx +350 -0
  76. package/src/serve/resident-runtime.ts +43 -3
  77. package/src/serve/routes/api.ts +476 -147
  78. package/src/serve/routes/sessions.ts +766 -0
  79. package/src/serve/security.ts +9 -0
  80. package/src/serve/server.ts +205 -1
  81. package/src/serve/session-automation.ts +146 -0
  82. package/src/sessions/archive.ts +348 -0
  83. package/src/sessions/automation-state.ts +444 -0
  84. package/src/sessions/automation-status.ts +239 -0
  85. package/src/sessions/automation.ts +1169 -0
  86. package/src/sessions/binding.ts +105 -0
  87. package/src/sessions/claude-hook.ts +240 -0
  88. package/src/sessions/config.ts +176 -0
  89. package/src/sessions/format.ts +191 -0
  90. package/src/sessions/import-child-env.ts +8 -0
  91. package/src/sessions/import-child.ts +152 -0
  92. package/src/sessions/parsers/claude-code.ts +259 -0
  93. package/src/sessions/parsers/codex.ts +303 -0
  94. package/src/sessions/parsers/hermes.ts +248 -0
  95. package/src/sessions/parsers/openclaw.ts +496 -0
  96. package/src/sessions/parsers/shared.ts +184 -0
  97. package/src/sessions/sanitize.ts +222 -0
  98. package/src/sessions/service.ts +1533 -0
  99. package/src/sessions/setup.ts +477 -0
  100. package/src/sessions/sources.ts +518 -0
  101. package/src/sessions/state.ts +118 -0
  102. package/src/sessions/types.ts +457 -0
  103. package/src/store/sqlite/adapter.ts +54 -15
  104. package/src/store/sqlite/scoped-index.ts +9 -0
  105. package/browser-extension/artifacts/gno-browser-clipper-v2.5.1.zip.sha256 +0 -1
@@ -21,5 +21,5 @@
21
21
  "content_security_policy": {
22
22
  "extension_pages": "script-src 'self'; object-src 'none'; connect-src http://127.0.0.1:*"
23
23
  },
24
- "version": "2.5.1"
24
+ "version": "2.6.0"
25
25
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gmickel/gno",
3
- "version": "2.5.1",
3
+ "version": "2.6.0",
4
4
  "description": "Local semantic search for your documents. Index Markdown, PDF, and Office files with hybrid BM25 + vector search.",
5
5
  "keywords": [
6
6
  "embeddings",
@@ -82,6 +82,7 @@
82
82
  "eval:hybrid": "bun --bun evalite evals/hybrid.eval.ts",
83
83
  "eval:memory": "bun --bun evalite evals/memory.eval.ts --threshold 100",
84
84
  "eval:memory:fixtures": "bun scripts/memory-eval-fixtures.ts",
85
+ "eval:sessions": "bun --bun evalite evals/sessions.eval.ts --threshold 100",
85
86
  "eval:hybrid:baseline": "bun scripts/hybrid-benchmark.ts --write",
86
87
  "eval:hybrid:delta": "bun scripts/hybrid-benchmark.ts --delta",
87
88
  "bench:ast-chunking": "bun scripts/ast-chunking-benchmark.ts",
package/spec/cli.md CHANGED
@@ -9,13 +9,13 @@ This document specifies the command-line interface for GNO, a local knowledge in
9
9
 
10
10
  ### Exit Codes
11
11
 
12
- | Code | Name | Description |
13
- | ---- | ----------- | ------------------------------------------------------------------------------------------ |
14
- | 0 | SUCCESS | Command completed successfully |
15
- | 1 | VALIDATION | Validation or usage error (bad args, missing required params) |
16
- | 2 | RUNTIME | Runtime failure (IO, DB, conversion, model, network) |
17
- | 3 | NOT_RUNNING | `--status`/`--stop` found no live matching process |
18
- | 4 | BUSY | Write-lease contention on `index` / `update` / `embed`; a lost `remember --supersede` race |
12
+ | Code | Name | Description |
13
+ | ---- | ----------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
14
+ | 0 | SUCCESS | Command completed successfully |
15
+ | 1 | VALIDATION | Validation or usage error (bad args, missing required params) |
16
+ | 2 | RUNTIME | Runtime failure (IO, DB, conversion, model, network) |
17
+ | 3 | NOT_RUNNING | `--status`/`--stop` found no live matching process |
18
+ | 4 | BUSY | Write-lease contention on `index` / `update` / `embed`; a lost `remember --supersede` race; a concurrent `sessions import`; a request ID still in progress (`REQUEST_PENDING`) |
19
19
 
20
20
  ### Global Flags
21
21
 
@@ -85,7 +85,9 @@ equivalent files fail closed as ambiguous.
85
85
  | ask | yes | no | no | yes | no | terminal |
86
86
  | capture | yes | no | no | no | no | terminal |
87
87
  | remember | yes | no | no | no | no | terminal |
88
+ | request-status | yes | no | no | no | no | terminal |
88
89
  | recall | yes | no | no | no | no | terminal |
90
+ | sessions | yes | no | no | no | no | terminal |
89
91
  | get | yes | no | no | yes | no | terminal |
90
92
  | multi-get | yes | yes | no | yes | no | terminal |
91
93
  | ls | yes | yes | no | yes | no | terminal |
@@ -1628,7 +1630,7 @@ Capture a note into an editable collection with structured provenance.
1628
1630
  **Synopsis:**
1629
1631
 
1630
1632
  ```bash
1631
- gno capture [content...] [--stdin|--file <path>] [--collection <name>] [--title <title>] [--path <relPath>] [--folder <relPath>] [--preset <id>] [--tags <tags>] [--collision-policy <policy>] [--source-kind <kind>] [--source-url <url>] [--source-title <title>] [--source-author <author>] [--source-date <date>] [--source-id <id>] [--json]
1633
+ gno capture [content...] [--stdin|--file <path>] [--collection <name>] [--title <title>] [--path <relPath>] [--folder <relPath>] [--preset <id>] [--tags <tags>] [--collision-policy <policy>] [--source-kind <kind>] [--source-url <url>] [--source-title <title>] [--source-author <author>] [--source-date <date>] [--source-id <id>] [--request-id <id>] [--json]
1632
1634
  ```
1633
1635
 
1634
1636
  **Content Sources:**
@@ -1684,8 +1686,33 @@ gno capture "thought to remember"
1684
1686
  gno capture --stdin --collection notes --preset source-summary --tags inbox,gno
1685
1687
  gno capture --file ./clip.md --source-url https://example.com --source-kind web --json
1686
1688
  gno capture "meeting note" --quiet
1689
+ gno capture "Release moves to Friday" --collection notes --request-id 0f8e5c1a-3c1e-4d0b-9a57-2f4f3b8f2c11 --json
1687
1690
  ```
1688
1691
 
1692
+ **Write and sync:**
1693
+
1694
+ - Planning, the write, and lexical sync run under the shared write lease
1695
+ (`.mcp-write.lock`), the same leased publication MCP `gno_capture` and REST
1696
+ `POST /api/capture` use. A lease held past the wait window fails with the
1697
+ busy error; nothing is written.
1698
+ - Without `--request-id`, a written file whose lexical sync fails still exits 0
1699
+ with `sync.status: "failed"` and `sync.error` in the receipt; `gno update`
1700
+ indexes it. `open_existing` on a file that is on disk but not indexed yet
1701
+ returns `sync.status: "skipped"` (`Existing file is not indexed yet.`).
1702
+
1703
+ **Request IDs:**
1704
+
1705
+ - `--request-id <id>` (1-128 of `A-Z a-z 0-9 . _ : -`, starting with a letter
1706
+ or digit) makes a retry of the same command safe.
1707
+ - With an ID, a written file whose lexical sync fails exits `RUNTIME` (2) and
1708
+ the request stays pending; rerunning with the same ID finishes it.
1709
+ - With an ID, `--json` adds
1710
+ `request: { requestId, status: "committed", replayed, committedAt }` to the
1711
+ capture receipt; terminal output adds `Request: <id> committed`, plus
1712
+ `(replayed, nothing written again)` on a replay.
1713
+ - Request error codes and exits: see [gno request-status](#gno-request-status).
1714
+ Semantics: `docs/guides/retries-and-request-ids.md`.
1715
+
1689
1716
  ---
1690
1717
 
1691
1718
  ### gno remember
@@ -1697,7 +1724,7 @@ write lease directly.
1697
1724
  **Synopsis:**
1698
1725
 
1699
1726
  ```bash
1700
- gno remember <text> --scope <scope> [--scope <scope>...] [--collection <name>] [--decision add|supersede | --add | --supersede <uri>] [--predecessor <uri>] [--predecessor-hash <hash>] [--receipt <path>] [--derived-from <uri>...] [--source <text>] [--caller <id>] [--session <id>] [--json]
1727
+ gno remember <text> --scope <scope> [--scope <scope>...] [--collection <name>] [--decision add|supersede | --add | --supersede <uri>] [--predecessor <uri>] [--predecessor-hash <hash>] [--receipt <path>] [--derived-from <uri>...] [--source <text>] [--caller <id>] [--session <id>] [--request-id <id>] [--json]
1701
1728
  ```
1702
1729
 
1703
1730
  **Scope and collection (fail-closed):**
@@ -1731,6 +1758,16 @@ gno remember <text> --scope <scope> [--scope <scope>...] [--collection <name>] [
1731
1758
  - A write returns success only after the file exists and lexical sync
1732
1759
  completed; the fact is retrievable before the command exits.
1733
1760
 
1761
+ **Request IDs:**
1762
+
1763
+ - `--request-id <id>` applies to writes only (`--add`, `--supersede`, or
1764
+ `--decision`); without a decision it fails `VALIDATION`
1765
+ (`REQUEST_ID_INVALID`). Rerunning the same write with the same ID is safe.
1766
+ - With an ID, `--json` adds
1767
+ `request: { requestId, status: "committed", replayed, committedAt }`;
1768
+ terminal output adds `Request: <id> committed`.
1769
+ - Semantics (replay, recovery, conflicts): `docs/guides/retries-and-request-ids.md`.
1770
+
1734
1771
  **Context fencing:**
1735
1772
 
1736
1773
  - `--receipt <path>` presents a recall receipt (the `recall --json` output or
@@ -1762,7 +1799,8 @@ predecessor, and fence errors; `BUSY` (4) when another writer holds the lease
1762
1799
  (`MEMORY_SUPERSEDE_CONFLICT`); `RUNTIME` (2) when the file was written but
1763
1800
  lexical sync failed (`MEMORY_SYNC_FAILED`) or the successor's `supersedes`
1764
1801
  edge did not project (`MEMORY_SUPERSEDE_PROJECTION_FAILED`). The JSON envelope carries the core code in
1765
- `details.memoryCode`.
1802
+ `details.memoryCode`. Request ID errors map as listed under
1803
+ [gno request-status](#gno-request-status) and carry `details.requestCode`.
1766
1804
 
1767
1805
  **Examples:**
1768
1806
 
@@ -1770,6 +1808,86 @@ edge did not project (`MEMORY_SUPERSEDE_PROJECTION_FAILED`). The JSON envelope c
1770
1808
  gno remember "Finn's kindergarten starts at 08:30" --scope family --add
1771
1809
  gno remember "Prod deploys from main only" --scope project:gno --scope ops
1772
1810
  gno remember "Prod deploys from release/*" --scope project:gno --supersede gno://memory/facts/2026/... --predecessor-hash <hash> --json
1811
+ gno remember "Prod deploys from main only" --scope project:gno --add --request-id 7d2e4b90-1f7a-4c2e-8f55-0b9c1d3e6a42 --json
1812
+ ```
1813
+
1814
+ ---
1815
+
1816
+ ### gno request-status
1817
+
1818
+ Look up a request ID sent with `gno capture`, `gno remember`, or a REST/Web UI
1819
+ document save before retrying the write. Read-only; takes no write lease.
1820
+
1821
+ **Synopsis:**
1822
+
1823
+ ```bash
1824
+ gno request-status <request-id> [--json]
1825
+ ```
1826
+
1827
+ **Behavior:**
1828
+
1829
+ - Reads the index's private request ledger in the local-owner namespace.
1830
+ Honors the global `--index` flag.
1831
+ - Returns a content-free pointer, never note or fact text. Status meanings and
1832
+ namespaces: `docs/guides/retries-and-request-ids.md`.
1833
+
1834
+ **Output:**
1835
+
1836
+ `--json` prints the [`request-status`](./output-schemas/request-status.schema.json)
1837
+ result:
1838
+
1839
+ ```json
1840
+ {
1841
+ "requestId": "0f8e5c1a-3c1e-4d0b-9a57-2f4f3b8f2c11",
1842
+ "status": "committed",
1843
+ "operation": "capture",
1844
+ "createdAt": "2026-09-24T08:00:00.000Z",
1845
+ "updatedAt": "2026-09-24T08:00:00.120Z",
1846
+ "result": {
1847
+ "uri": "gno://notes/inbox/2026-09-24/capture-3f9c.md",
1848
+ "docid": "#a1b2c3",
1849
+ "contentHash": "<sha256>"
1850
+ }
1851
+ }
1852
+ ```
1853
+
1854
+ - `status`: `pending` | `committed` | `expired` | `not_found`.
1855
+ - `operation`: `capture` | `remember` | `document.update`; `createdAt`,
1856
+ `updatedAt`, and `operation` are absent for `not_found`.
1857
+ - `result` only for `committed`: `uri`, `docid`, and `contentHash` (capture,
1858
+ remember) or `sourceHash` (document update).
1859
+
1860
+ Terminal output prints `Request:`, `Status:`, and, when present,
1861
+ `Operation:`, `Updated:`, and `URI:` lines, then one next-step line:
1862
+
1863
+ | Status | Next-step line |
1864
+ | ----------- | ------------------------------------------------------------------------------------------------- |
1865
+ | `committed` | `Committed: do not resend; the retained outcome replays.` |
1866
+ | `pending` | `Pending: retry the same command with the same --request-id to finish it.` |
1867
+ | `expired` | `Expired: this ID already ran and will not run again; check current state before using a new ID.` |
1868
+ | `not_found` | `Not found: nothing was accepted under this ID.` |
1869
+
1870
+ **Request error codes** (every CLI surface that takes a request ID; the JSON
1871
+ error envelope carries the request code in `details.requestCode`):
1872
+
1873
+ | Request code | CLI code | Exit |
1874
+ | ---------------------------- | ------------ | ---- |
1875
+ | `REQUEST_ID_INVALID` | `VALIDATION` | 1 |
1876
+ | `REQUEST_ID_CONFLICT` | `VALIDATION` | 1 |
1877
+ | `REQUEST_EXPIRED` | `VALIDATION` | 1 |
1878
+ | `REQUEST_PENDING` | `BUSY` | 4 |
1879
+ | `REQUEST_RECOVERY_CONFLICT` | `RUNTIME` | 2 |
1880
+ | `REQUEST_CAPACITY_EXHAUSTED` | `RUNTIME` | 2 |
1881
+ | `REQUEST_LEDGER_UNAVAILABLE` | `RUNTIME` | 2 |
1882
+
1883
+ `gno request-status` itself exits `VALIDATION` (1) for a malformed ID and
1884
+ `RUNTIME` (2) when the ledger exists but cannot be opened.
1885
+
1886
+ **Examples:**
1887
+
1888
+ ```bash
1889
+ gno request-status 0f8e5c1a-3c1e-4d0b-9a57-2f4f3b8f2c11
1890
+ gno request-status 0f8e5c1a-3c1e-4d0b-9a57-2f4f3b8f2c11 --json
1773
1891
  ```
1774
1892
 
1775
1893
  ---
@@ -1823,6 +1941,206 @@ gno recall "kindergarten" --scope family --max-facts 3 --json > receipt.json
1823
1941
 
1824
1942
  ---
1825
1943
 
1944
+ ### gno sessions
1945
+
1946
+ Discover and manually import local agent sessions (Codex, Claude Code,
1947
+ OpenClaw, Hermes) into a dedicated session archive. Thin adapters over the
1948
+ core sessions service (`src/sessions/service.ts`). A fresh installation
1949
+ imports, watches, hooks and schedules nothing; every import is an explicit
1950
+ invocation.
1951
+
1952
+ **Archive pair (binding):**
1953
+
1954
+ - A session archive is one dedicated config file (carrying a `sessions`
1955
+ block) paired with one named index. Every archive command passes both
1956
+ explicitly: `gno --config <archive.yml> --index <name> sessions ...`.
1957
+ - `sessions init` refuses the default config file and the `default` index.
1958
+ - Before every command (all of `gno`, not only `sessions`), a config whose
1959
+ `sessions.index` differs from `--index` exits `VALIDATION`
1960
+ (`SESSIONS_BINDING_MISMATCH`), and an index recorded as an archive exits
1961
+ `VALIDATION` when opened with any other config (including cross-index
1962
+ `get`). Plain `gno update` on the default config therefore never reads the
1963
+ archive.
1964
+ - The archive root must lie outside GNO's config/data/cache directories so
1965
+ `gno reset`, index cleanup or uninstall cannot remove it, and outside every
1966
+ folder the default config indexes (`SESSIONS_UNSAFE_PATH`).
1967
+
1968
+ **Synopsis:**
1969
+
1970
+ ```bash
1971
+ gno sessions [discover] [--json]
1972
+ gno --config <archive.yml> --index <name> sessions init --archive <dir> --collection <name> [--json]
1973
+ gno --config <archive.yml> --index <name> sessions source add <id> --harness <codex|claude-code|openclaw|hermes> --path <root> --collection <name> [--project <prefix>=<collection>...] [--json]
1974
+ gno --config <archive.yml> --index <name> sessions source remove <id> [--json]
1975
+ gno --config <archive.yml> --index <name> sessions import (--source <id> | <paths...> --collection <name>) [--format <harness>] [--dry-run] [--limit <n>] [--json]
1976
+ gno --config <archive.yml> --index <name> sessions status [--json]
1977
+ gno --config <archive.yml> --index <name> sessions prune --source <id> [--apply] [--json]
1978
+ gno --config <archive.yml> --index <name> sessions automation set <profile> --source <id>... [--cadence <n>s|m|h|d] [--limit <n>] [--retries <n>] [--json]
1979
+ gno --config <archive.yml> --index <name> sessions automation preview <profile> [--settings <file>] [--json]
1980
+ gno --config <archive.yml> --index <name> sessions automation enable <profile> [--hook claude-code [--settings <file>]] [--schedule --cadence <n>s|m|h|d] [--json]
1981
+ gno --config <archive.yml> --index <name> sessions automation disable <profile> [--hook] [--schedule] [--json]
1982
+ gno --config <archive.yml> --index <name> sessions automation remove <profile> [--json]
1983
+ gno --config <archive.yml> --index <name> sessions automation run <profile> [--json]
1984
+ gno --config <archive.yml> --index <name> sessions hook claude-code --profile <id>
1985
+ ```
1986
+
1987
+ **discover** (default): previews supported local roots (`$CODEX_HOME` or
1988
+ `~/.codex/sessions`; `~/.claude/projects` and `$CLAUDE_CONFIG_DIR/projects`;
1989
+ `$OPENCLAW_STATE_DIR` or `~/.openclaw`; `$HERMES_HOME` or `~/.hermes`) with
1990
+ unit counts, sizes and sampled format versions. Never imports and needs no
1991
+ archive. Output: `sessions-discovery` schema.
1992
+
1993
+ **init**: creates or extends the archive config (idempotent). Adds the
1994
+ `sessions` block (`index`, `archiveRoot`) and one archive collection at
1995
+ `<archive>/<collection>` with the JSONL record mapping. A config already bound
1996
+ to another index or root is never retargeted.
1997
+
1998
+ **source add / remove**: registers an owner-approved source root, file or
1999
+ database with a default archive collection (created under the archive root
2000
+ when missing). `--project <prefix>=<collection>` maps recorded working
2001
+ directories under `prefix` to another archive collection. Removing a source
2002
+ keeps its archive. Registration never imports.
2003
+
2004
+ **import**: parses the selected source (or explicit paths), classifies turns
2005
+ structurally, redacts, and writes one sanitized JSONL archive file per
2006
+ thread, then syncs the changed files through the ordinary JSONL record
2007
+ adapter.
2008
+
2009
+ - Selection is required: `--source <id>` (uses the registered collection and
2010
+ project mappings) or explicit absolute paths plus `--collection`.
2011
+ `--collection` with `--source` is rejected.
2012
+ - `--format` overrides structural detection for path imports.
2013
+ - `--dry-run` parses and reports without writing archive files, checkpoint
2014
+ state or index rows.
2015
+ - `--limit <n>` bounds the number of changed units processed; unchanged units
2016
+ do not count; the rest are reported as `deferredUnits`.
2017
+ - Reruns are idempotent: a unit whose fingerprint, parser, redaction and
2018
+ archive format are unchanged is skipped; a changed unit is re-rendered and
2019
+ compared with the archived bytes. Turn IDs are stable across appends.
2020
+ - A unit whose final line is cut mid-write, or whose structure drifted (for
2021
+ example assistant turns without any recognised human turn), is
2022
+ `incomplete`: its readable threads are archived but its checkpoint does not
2023
+ advance, and the next run retries it.
2024
+ - A thread whose recorded working directories map to different collections
2025
+ is quarantined (`skipped_policy`, reason `mixed_domain`) instead of being
2026
+ written to the less restricted one.
2027
+ - A unit is identified by source ID plus its safe locator, so moving a file
2028
+ within the source root or re-registering the source at a new path keeps
2029
+ its archive files; two units with the same locator fail the second one
2030
+ (`unit_conflict`). Archive files are namespaced per unit, so two units
2031
+ reporting the same thread ID never overwrite each other.
2032
+ - A unit is re-imported when its routing settings (collection or project
2033
+ mappings) change, so a quarantined thread is imported once it is mapped.
2034
+ - Units are recorded complete only after the lexical sync of the changed
2035
+ archive files succeeds; a failed or interrupted sync is retried by the next
2036
+ run. Units with malformed records stay `incomplete` (`malformed_records`).
2037
+ - A thread withheld by policy (`mixed_domain`, `over_limit`; a thread at the
2038
+ turn limit is skipped whole) has any earlier archive copy moved to
2039
+ `<archive>/.gno-sessions/withheld/` and removed from the index.
2040
+ - A registered source whose root is missing or cannot be listed still gets
2041
+ archive-only maintenance (redaction rescans), then the import fails with
2042
+ `SESSIONS_SOURCE_UNAVAILABLE` (exit 2). A directory or unit file inside a
2043
+ source that cannot be read is a `failed` unit (`permission_denied`,
2044
+ `source_missing` or `read_failed`; directories use the locator `.`), so the
2045
+ receipt is never `nothing_to_do`, and its checkpoint does not advance.
2046
+ - Imports on one archive serialize on `<archive>/.gno-sessions/import.lock`;
2047
+ a concurrent run exits `BUSY` (`SESSIONS_BUSY`).
2048
+ - A source file that disappears keeps its archive; `status` reports it as
2049
+ `sourceUnavailable`. When the redaction rules or the configured literals
2050
+ (`sessions.redaction.literals`) change, units with a source are re-rendered
2051
+ and archives without a source are rescanned in place; a parser change
2052
+ cannot reparse a missing source and is reported instead.
2053
+ - Output: `sessions-import-receipt` schema. `status` is `complete`,
2054
+ `partial` (any incomplete, failed, unsupported or deferred unit, or failed
2055
+ lexical sync), `failed` (nothing archived or unchanged and nothing
2056
+ incomplete, for example every selected unit unsupported or failed) or
2057
+ `nothing_to_do`. Units skipped as already current count their archived
2058
+ threads as `unchanged`; an unsupported unit selected as a file is reported
2059
+ by its (redacted) file name.
2060
+ Receipts carry counts, per-unit outcomes with safe locators (never host
2061
+ paths), lexical readiness and the embedding backlog. Embeddings are not
2062
+ generated by import; run `gno embed` on the archive pair.
2063
+
2064
+ **status**: archive collections with thread counts, and per source its
2065
+ availability (`false` when the root is missing or cannot be read), unit counts (complete, incomplete, failed, pending),
2066
+ `sourceUnavailable`, `staleParser` and last import time, plus the
2067
+ `automation` block (daemon state, per-profile state, triggers, pending and
2068
+ running work, last run, last success, next due time only with a live
2069
+ daemon, recovery action). Output: `sessions-status` schema.
2070
+
2071
+ **automation** (opt-in; nothing is enabled by install, upgrade, repair or
2072
+ restart):
2073
+
2074
+ - `set` creates or reconfigures a profile in `sessions.automation` of the
2075
+ archive config: registered `--source` IDs (1-64), optional `--cadence`
2076
+ (`<n>s|m|h|d`, 1m..30d), `--limit` (changed units per source per run,
2077
+ default 200) and `--retries` (0-10, default 3). Triggers keep their state;
2078
+ a new profile has none. Unknown sources exit `VALIDATION`
2079
+ (`SESSIONS_UNKNOWN_SOURCE`). Output: the preview object.
2080
+ - `preview` prints sources with host paths, destination collections, the
2081
+ hook command and target settings file (`--settings`, else
2082
+ `$CLAUDE_CONFIG_DIR/settings.json` or `~/.claude/settings.json`), the
2083
+ schedule, the budget, and the daemon prerequisite. Local only.
2084
+ - `enable --hook claude-code` installs exactly one owned SessionEnd entry
2085
+ (identified by its command for this config and profile; other entries are
2086
+ preserved; a `.bak` copy is kept; invalid JSON is left untouched and exits
2087
+ `VALIDATION`) and then sets `hook.enabled`. Other harnesses exit
2088
+ `VALIDATION` with `SESSIONS_UNSUPPORTED_INTEGRATION`. `enable --schedule`
2089
+ requires a cadence (flag or profile); the first run is due one cadence
2090
+ later. Enabling never installs or starts a service.
2091
+ - `disable` switches the selected triggers off (both when none is named),
2092
+ removes the owned hook entry, and clears pending work admitted by those
2093
+ triggers; a run in progress finishes. `remove` uninstalls the owned entry
2094
+ (failing closed when the settings file cannot be read) and deletes the
2095
+ profile and its run state. Archives are never deleted.
2096
+ - `run` admits a manual trigger and runs the profile through the importer
2097
+ (`sessions import --source` per source, bounded by `limit`). Output:
2098
+ `sessions-automation-run` schema; exit `BUSY` (4, `SESSIONS_BUSY`) when the
2099
+ run failed with reason `busy` (another import, lease holder or a locked
2100
+ index; the busy run is recorded), exit `RUNTIME` (2) when the outcome is
2101
+ `failed`.
2102
+
2103
+ **hook**: `sessions hook claude-code --profile <id>` is the command an
2104
+ installed hook runs. It reads the event JSON on stdin (at most 64 KiB), skips
2105
+ anything other than `SessionEnd`, rechecks under the marker lock that the
2106
+ profile's hook is enabled, and durably records one pending generation. It
2107
+ never imports, parses sessions or uses the network, and waits at most 1 s for
2108
+ the lock. Output is one content-free line: `accepted (…pending, not yet
2109
+ archived…)`, `skipped (…)` (exit 0), or `not accepted (…)` (exit 2).
2110
+ `GNO_SESSIONS_HOOKS=off` or `0` skips immediately. An unknown profile is
2111
+ reported as `skipped (… unknown_profile)`, a profile whose hook is off as
2112
+ `skipped (… hook_disabled)`. An explicit `--settings` other than the default
2113
+ location must name an existing file (`VALIDATION`).
2114
+
2115
+ **prune**: lists archived units whose source is gone (preview by default);
2116
+ `--apply` deletes exactly those archive files and syncs the index, never a
2117
+ file a still-present unit references. It requires a complete listing of the
2118
+ source and fails with `SESSIONS_SOURCE_UNAVAILABLE` when part of it cannot be
2119
+ read or the listing was truncated. It plans under the archive lock; when
2120
+ the index sync fails it records nothing, returns `applied: false` with an
2121
+ `error`, and the next prune retries. Source deletion alone never removes
2122
+ archive files.
2123
+
2124
+ **Exit codes:** `VALIDATION` (1) for selection, destination, binding,
2125
+ unknown source/collection, unsafe path and unsupported format errors;
2126
+ `BUSY` (4) for `SESSIONS_BUSY`; `RUNTIME` (2) for an import or automation
2127
+ run whose status is `failed` and for a hook that was not accepted, except `VALIDATION` (1, `SESSIONS_UNSUPPORTED_FORMAT`) when no
2128
+ selected unit is a supported format. The JSON error envelope carries the core code in
2129
+ `details.sessionsCode`.
2130
+
2131
+ **Examples:**
2132
+
2133
+ ```bash
2134
+ gno sessions
2135
+ gno --config ~/gno-sessions/archive.yml --index sessions sessions init --archive ~/gno-sessions/archive --collection sessions-work
2136
+ gno --config ~/gno-sessions/archive.yml --index sessions sessions source add codex --harness codex --path ~/.codex/sessions --collection sessions-work
2137
+ gno --config ~/gno-sessions/archive.yml --index sessions sessions import --source codex --dry-run
2138
+ gno --config ~/gno-sessions/archive.yml --index sessions sessions import --source codex --json
2139
+ gno --config ~/gno-sessions/archive.yml --index sessions query "why did we pick sqlite" --category harness/codex --author human
2140
+ ```
2141
+
2142
+ ---
2143
+
1826
2144
  ### gno get
1827
2145
 
1828
2146
  Retrieve a single document by reference.
@@ -4119,6 +4437,8 @@ Errors are written to stderr. With `--json` flag, errors are also returned as:
4119
4437
  ```
4120
4438
 
4121
4439
  Error codes match exit codes: `VALIDATION` (exit 1), `RUNTIME` (exit 2), `NOT_RUNNING` (exit 3), `BUSY` (exit 4).
4440
+ Request ID errors keep their stable request code in `details.requestCode`
4441
+ (see [gno request-status](#gno-request-status)).
4122
4442
 
4123
4443
  Write-lease contention on `index` / `update` / `embed` does not use the generic envelope. Text mode writes the dedicated "index is busy" message to stderr; `--json` writes `{ success: false, error, contention }` to stdout. Both exit 4. `gno audit` also uses exit 4 for findings.
4124
4444
 
@@ -4130,20 +4450,23 @@ Write-lease contention on `index` / `update` / `embed` does not use the generic
4130
4450
 
4131
4451
  ## Environment Variables
4132
4452
 
4133
- | Variable | Description |
4134
- | -------------------------- | -------------------------------------------------------------------------------------------------------------------------- |
4135
- | `GNO_CONFIG_DIR` | Override config directory |
4136
- | `GNO_DATA_DIR` | Override data directory (DB location) |
4137
- | `GNO_CACHE_DIR` | Override cache directory (models) |
4138
- | `NO_COLOR` | Disable colored output (standard) |
4139
- | `PAGER` | Pager for long output (default: less -R on Unix, built-in on Windows) |
4140
- | `GNO_SKILLS_HOME_OVERRIDE` | Override home dir for skill user scope (testing) |
4141
- | `GNO_MEMORY_CALLER` | Default `--caller` identity for `gno remember` / `gno recall` |
4142
- | `GNO_MEMORY_SESSION` | Default `--session` identity for `gno remember` / `gno recall` |
4143
- | `CLAUDE_SKILLS_DIR` | Override Claude skills directory |
4144
- | `CODEX_SKILLS_DIR` | Override Codex skills directory |
4145
- | `CLAUDE_CONFIG_DIR` | Claude Code config dir; `gno agents` resolves Claude's instruction file under it (suppressed by an explicit home override) |
4146
- | `CODEX_HOME` | Codex config dir; same rule as `CLAUDE_CONFIG_DIR` |
4453
+ | Variable | Description |
4454
+ | -------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
4455
+ | `GNO_CONFIG_DIR` | Override config directory |
4456
+ | `GNO_DATA_DIR` | Override data directory (DB location) |
4457
+ | `GNO_CACHE_DIR` | Override cache directory (models) |
4458
+ | `NO_COLOR` | Disable colored output (standard) |
4459
+ | `PAGER` | Pager for long output (default: less -R on Unix, built-in on Windows) |
4460
+ | `GNO_SKILLS_HOME_OVERRIDE` | Override home dir for skill user scope (testing) |
4461
+ | `GNO_MEMORY_CALLER` | Default `--caller` identity for `gno remember` / `gno recall` |
4462
+ | `GNO_MEMORY_SESSION` | Default `--session` identity for `gno remember` / `gno recall` |
4463
+ | `CLAUDE_SKILLS_DIR` | Override Claude skills directory |
4464
+ | `CODEX_SKILLS_DIR` | Override Codex skills directory |
4465
+ | `CLAUDE_CONFIG_DIR` | Claude Code config dir; `gno agents` resolves Claude's instruction file under it (suppressed by an explicit home override); `gno sessions discover` also checks its `projects/` |
4466
+ | `CODEX_HOME` | Codex config dir; same rule as `CLAUDE_CONFIG_DIR`; `gno sessions discover` checks its `sessions/` |
4467
+ | `OPENCLAW_STATE_DIR` | OpenClaw state dir checked by `gno sessions discover` (else `$OPENCLAW_HOME/.openclaw` or `~/.openclaw`) |
4468
+ | `HERMES_HOME` | Hermes home checked by `gno sessions discover` (else `~/.hermes`) |
4469
+ | `GNO_SESSIONS_HOOKS` | `off` or `0` makes every installed `gno sessions hook` return immediately without admitting work |
4147
4470
 
4148
4471
  ---
4149
4472