Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
148 commits
Select commit Hold shift + click to select a range
43143d1
feat(state): harden global sqlite project identity
levifig Jun 13, 2026
e6cb30f
fix(state): tighten project path and relationship invariants
levifig Jun 13, 2026
9f72cd9
fix(state): remove legacy project id fallback
levifig Jun 13, 2026
ebffbb0
fix(cli): make state-backed help consistent
levifig Jun 13, 2026
41a809d
feat(project): list global sqlite identities
levifig Jun 13, 2026
afce497
feat(state): add doctor repair dry run
levifig Jun 13, 2026
0ea39e8
feat(state): diagnose sqlite invariant drift
levifig Jun 13, 2026
2b5fc53
feat(state): repair missing relationship origins
levifig Jun 13, 2026
c7c824c
feat(state): archive migrated legacy databases
levifig Jun 13, 2026
89c0cae
fix(state): stabilize empty json arrays
levifig Jun 13, 2026
4583477
feat(state): verify sqlite backups
levifig Jun 13, 2026
0ddf3b9
feat(state): add export manifest counts
levifig Jun 13, 2026
133e284
feat(state): diagnose backend mapping drift
levifig Jun 13, 2026
88718eb
fix(state): dedupe doctor repair actions
levifig Jun 13, 2026
e73d09f
feat(project): add move dry run
levifig Jun 13, 2026
50c1abf
feat(project): preview renames read-only
levifig Jun 13, 2026
0094ac6
fix(state): verify backups read-only
levifig Jun 13, 2026
e07991b
feat(state): add export table count
levifig Jun 13, 2026
740066e
fix(state): read exports without writes
levifig Jun 13, 2026
c18e5e8
fix(cli): list valid task statuses
levifig Jun 13, 2026
d8314dd
fix(cli): list valid task priorities
levifig Jun 13, 2026
6a142bc
fix(cli): align generated task reference values
levifig Jun 13, 2026
c4e6557
fix(cli): expose project safeguards in metadata
levifig Jun 13, 2026
ecdb892
fix(cli): document project list metadata
levifig Jun 13, 2026
1c1d266
fix(cli): restore state repair metadata
levifig Jun 13, 2026
3134bdc
fix(cli): return JSON project errors
levifig Jun 13, 2026
b4d870b
fix(cli): return JSON state errors
levifig Jun 13, 2026
3469374
fix(cli): return JSON backup errors
levifig Jun 13, 2026
ff40dd1
fix(cli): return JSON lifecycle errors
levifig Jun 13, 2026
8b9a4fa
fix(cli): return JSON task errors
levifig Jun 13, 2026
ef117c4
fix(cli): return JSON trace errors
levifig Jun 13, 2026
6b4045b
fix(cli): align link create flags
levifig Jun 13, 2026
50fc34c
fix(cli): normalize JSON error fallback
levifig Jun 13, 2026
53e00f4
docs(cli): document task JSON options
levifig Jun 13, 2026
e75c506
test(cli): guard agent help JSON options
levifig Jun 13, 2026
c407564
fix(cli): show trace help
levifig Jun 13, 2026
58660df
fix(cli): show check help
levifig Jun 13, 2026
097fbff
fix(cli): show migrate help
levifig Jun 13, 2026
edbd0ea
fix(state): warn on unmapped linear tasks
levifig Jun 13, 2026
96ff1af
fix(cli): document artifact commands for agents
levifig Jun 13, 2026
cb94f12
docs(cli): expand generated CLI reference
levifig Jun 13, 2026
e105bd5
docs(cli): document state export commands
levifig Jun 13, 2026
60c880e
docs(cli): clarify report format help
levifig Jun 13, 2026
2e684e7
docs(cli): clarify report status filters
levifig Jun 13, 2026
a265491
fix(cli): show kb subcommand help
levifig Jun 13, 2026
d6e4d8d
docs(cli): document worktree storage migration flags
levifig Jun 13, 2026
bb24940
fix(cli): align report create help
levifig Jun 13, 2026
8b5df6c
docs(cli): document housekeeping legacy filters
levifig Jun 13, 2026
0cb0f21
docs(cli): align build install agent options
levifig Jun 13, 2026
194ff4c
docs(cli): document generic state export format
levifig Jun 13, 2026
8ee2d97
fix(state): distinguish legacy project keys in status
levifig Jun 13, 2026
1c394af
fix(project): keep identity reads read-only
levifig Jun 13, 2026
fbae025
fix(project): avoid empty state on rejected moves
levifig Jun 13, 2026
7837de4
fix(project): require identity before rename
levifig Jun 13, 2026
ba0c27c
fix(state): diagnose sqlite integrity drift
levifig Jun 13, 2026
94b2e28
fix(state): report backup foreign key checks
levifig Jun 13, 2026
1722406
fix(state): report export integrity checks
levifig Jun 13, 2026
2f628be
fix(state): detail foreign key verification failures
levifig Jun 13, 2026
20a3001
fix(state): inspect sqlite read-only
levifig Jun 13, 2026
2b6b420
fix(state): surface project identity in exports
levifig Jun 13, 2026
219bbc4
fix(state): report backup sha256
levifig Jun 13, 2026
be439a1
fix(state): version json contracts
levifig Jun 13, 2026
c4fbcac
fix(cli): version json errors
levifig Jun 13, 2026
82c151f
fix(state): version status json
levifig Jun 13, 2026
42105fe
fix(project): version identity json
levifig Jun 13, 2026
b6ba830
fix(project): alias identity to show
levifig Jun 13, 2026
0b63c5f
fix(migrate): allow markdown-only task imports
levifig Jun 13, 2026
ce67bd9
fix(state): version migration repair json
levifig Jun 13, 2026
750b8a3
fix(state): clarify repair dry runs
levifig Jun 13, 2026
6dfc80c
fix(state): validate backend mapping fields
levifig Jun 13, 2026
75ababd
fix(project): require move target directory
levifig Jun 13, 2026
ea5eec2
fix(state): surface global backup scope
levifig Jun 13, 2026
e0b39d1
fix(state): report backup project count
levifig Jun 13, 2026
232b5fd
docs(cli): sync project identity alias reference
levifig Jun 13, 2026
b164c96
fix(state): declare export snapshot scope
levifig Jun 13, 2026
07b440a
fix(state): warn on unknown backend sync status
levifig Jun 13, 2026
24b5347
fix(migrate): report markdown import project identity
levifig Jun 14, 2026
91432ac
fix(migrate): report storage-home project scope
levifig Jun 14, 2026
de968a6
fix(state): report diagnostic database scope
levifig Jun 14, 2026
46b67ad
fix(repair): report project scope
levifig Jun 14, 2026
f740ac4
fix(project): report global identity scope
levifig Jun 14, 2026
c6cf5a6
fix(task): report mutation project scope
levifig Jun 14, 2026
c8f8929
fix(spec): report archive project scope
levifig Jun 14, 2026
f23e5b7
fix(link): report relationship project scope
levifig Jun 14, 2026
f9a07ac
fix(tag): report tag project scope
levifig Jun 14, 2026
4e8fb64
fix(bundle): report bundle project scope
levifig Jun 14, 2026
b1e90a0
fix(idea): report idea project scope
levifig Jun 14, 2026
f6d5c06
fix(spark): report spark project scope
levifig Jun 14, 2026
bb48657
fix(brainstorm): report brainstorm project scope
levifig Jun 14, 2026
7611a67
fix(report): report lifecycle project scope
levifig Jun 14, 2026
49b7c7b
fix(state): warn on unimported local markdown
levifig Jun 14, 2026
52fc160
fix(session): report session project scope
levifig Jun 14, 2026
bfdb726
fix(task): report task read project scope
levifig Jun 14, 2026
33d874b
fix(trace): report read project scope
levifig Jun 14, 2026
9e0c8c3
fix(housekeeping): report project scope
levifig Jun 14, 2026
8d7883e
fix(cli): version compatibility summaries
levifig Jun 14, 2026
998fdaa
fix(state): verify sqlite backups
levifig Jun 14, 2026
f1e0747
fix(state): export project path history
levifig Jun 14, 2026
86d3fd8
fix(state): validate project backend mappings
levifig Jun 14, 2026
3dd854b
feat(state): add json path output
levifig Jun 14, 2026
e209728
fix(state): include backup path in verify errors
levifig Jun 14, 2026
7e8d25b
fix(state): include doctor repair plans
levifig Jun 14, 2026
4d03b88
fix(state): avoid invalid repair export loop
levifig Jun 14, 2026
113e941
feat(state): accept json export alias
levifig Jun 14, 2026
b6f6b2d
docs(state): define boring reliable plan
levifig Jun 14, 2026
83becfd
test(state): cover control plane json failures
levifig Jun 14, 2026
3ef777e
docs(state): focus boring reliable execution
levifig Jun 14, 2026
aeaaf25
test(state): cover control plane json successes
levifig Jun 14, 2026
a27297f
test(state): prove control plane safeguards
levifig Jun 14, 2026
f2b1eda
docs(state): verify manual backup restore
levifig Jun 14, 2026
00d8345
fix(state): guide verified backup restores
levifig Jun 14, 2026
919bef3
fix(state): classify repair action policy
levifig Jun 14, 2026
2f71a81
test(state): prove repair plan commands
levifig Jun 14, 2026
e76da82
fix(state): label backend diagnostic policy
levifig Jun 14, 2026
bb5fb49
fix(project): normalize identity change output
levifig Jun 14, 2026
9cd5055
fix(migrate): normalize human output
levifig Jun 14, 2026
c5d2825
fix(project): normalize read output
levifig Jun 14, 2026
09cb646
feat(state): add verbose path output
levifig Jun 14, 2026
94c5b83
fix(state): guide backup verification
levifig Jun 14, 2026
6b593d4
fix(state): normalize identity output
levifig Jun 14, 2026
e1ea936
fix(export): include project context in markdown
levifig Jun 14, 2026
44d5a1a
fix(report): add JSON output for generated reports
levifig Jun 14, 2026
409c3c6
fix(export): stabilize json format conflicts
levifig Jun 14, 2026
09b2b4d
fix(state): reject sensitive backend mappings
levifig Jun 14, 2026
66b692f
fix(project): accept positional move paths
levifig Jun 14, 2026
882ec6d
fix(project): clarify missing state errors
levifig Jun 14, 2026
387f887
fix(project): reject schema drift
levifig Jun 14, 2026
2929947
fix(project): reject path invariant drift
levifig Jun 14, 2026
2278221
fix: structure backend diagnostic details
levifig Jun 14, 2026
e693e8f
chore: build update bundled CLI
levifig Jun 14, 2026
a7d948a
fix: expose backup restore targets
levifig Jun 14, 2026
b5bf559
chore: build update bundled CLI
levifig Jun 14, 2026
fde59c6
fix: identify markdown import action
levifig Jun 14, 2026
a1ad7b1
fix: preserve export repair context
levifig Jun 14, 2026
9ebff21
fix: classify state warning diagnostics
levifig Jun 14, 2026
556ce9c
fix: enrich markdown dry-run json
levifig Jun 14, 2026
b138a04
fix: contextualize state missing errors
levifig Jun 14, 2026
2f4f22c
fix: enrich report generate json
levifig Jun 14, 2026
aff7e26
fix: report storage migration identity
levifig Jun 14, 2026
b3da127
docs: align agent help json contracts
levifig Jun 14, 2026
fe4625a
fix: clarify state json help
levifig Jun 14, 2026
cd4b752
fix: align session report json
levifig Jun 14, 2026
8de4d56
fix: clarify entity json help
levifig Jun 14, 2026
76d3326
fix: clarify utility json help
levifig Jun 14, 2026
1a3583a
fix: clarify state json help
levifig Jun 14, 2026
d1129f8
docs: complete reliability audit
levifig Jun 14, 2026
eb2cbb1
ci: add homebrew release pipeline
levifig Jun 14, 2026
3e3f4bd
chore: release v2.0.0-pre.20260614235428
levifig Jun 14, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
10 changes: 5 additions & 5 deletions .agents/specs/SPEC-040-sqlite-backed-loaf-operational-state.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ SPEC-010 deliberately introduced `TASKS.json` as structured metadata because dir

## Solution Direction

Introduce a project-scoped SQLite store for Loaf operational state, stored outside the repository under XDG paths and accessed only through the Loaf CLI.
Introduce a single SQLite store for Loaf operational state, stored outside the repository under XDG paths, partitioned by stable project ID, and accessed only through the Loaf CLI.

The SQLite state layer starts in Go. ADR-014 makes Go the intended home for Loaf's stateful runtime and lower-dependency command surface. The existing TypeScript CLI remains a compatibility implementation during migration, but new SQLite-backed runtime work should not deepen the Node/TypeScript dependency footprint.

Expand Down Expand Up @@ -393,7 +393,7 @@ Decision criteria:
not sufficient; SQLite driver upgrades also need release-note review because
embedded SQLite code may carry non-Go vulnerability context.
- **Testability:** Track A must include a real SQLite smoke test that opens the
project database, applies migrations, writes a row, reads it back, and runs
global project-partitioned database, applies migrations, writes a row, reads it back, and runs
with `CGO_ENABLED=0`.

Implementation constraints for Track A:
Expand Down Expand Up @@ -449,8 +449,8 @@ Implementation constraints for Track A:

## Open Questions

- [x] Exact XDG split: should the project database live under `$XDG_STATE_HOME/loaf/` or `$XDG_DATA_HOME/loaf/`? Decision: SQLite operational state lives under `$XDG_STATE_HOME/loaf/projects/<project-id>/loaf.sqlite`, with platform fallbacks handled by the Go `PathResolver`; it is state, not portable user data.
- [x] How should project identity be derived for moved repositories: absolute path hash, git remote, git common-dir, explicit project UUID, or a combination? Decision: SPEC-040 hashes the resolved canonical project root. Git linked worktrees resolve through `git-common-dir` to the main checkout root, so sibling worktrees share state. Move-stable project UUIDs remain future migration work.
- [x] Exact XDG split: should the database live under `$XDG_STATE_HOME/loaf/` or `$XDG_DATA_HOME/loaf/`? Decision: SQLite operational state lives in one global database at `$XDG_DATA_HOME/loaf/loaf.sqlite`, with rows partitioned by project ID and platform fallbacks handled by the Go `PathResolver`.
- [x] How should project identity be derived for moved repositories: absolute path hash, git remote, git common-dir, explicit project UUID, or a combination? Decision: new projects get a generated stable project ID stored in SQLite, plus a friendly name and path mapping. Legacy path hashes remain only as an adoption key for imported/migrated rows. Use `loaf project rename <name>` for friendly-name changes and `loaf project move --from <old-path>` when a checkout path changes.
- [x] What is the exact TypeScript delegation mechanism for unmigrated commands: subprocess to bundled JS, embedded assets, or npm-package-local path? Decision: the Go front controller runs a subprocess through `node dist-cli/index.js`, resolving the bundled script from the working tree/project root/executable-relative paths, with `LOAF_LEGACY_CLI` as an override for development.
- [x] Should Markdown compatibility views be generated automatically after every mutation, or only by explicit export commands? Decision: SQLite-backed commands do not write repository Markdown as a side effect. Compatibility Markdown remains import/fallback input, and reviewable views are produced by explicit export/report commands unless a later compatibility task deliberately adds a generated view command.
- [x] What is the minimum session transcript row shape that works across Claude Code, Codex, OpenCode, Cursor, Gemini, and Amp? Decision: store structured session rows plus journal summaries/pointers first: session alias, harness session ID, branch, status, optional source, and journal rows with type, scope, message, observed branch/worktree/harness ID, and nullable session/spec/task links. Raw transcript capture stays harness-native/out of scope until redaction controls are designed.
Expand All @@ -460,7 +460,7 @@ Implementation constraints for Track A:

## Test Conditions

- [x] `loaf state init` creates a project-scoped SQLite database outside the repository and prints its path without creating secrets.
- [x] `loaf state init` creates the global project-partitioned SQLite database outside the repository and prints its path without creating secrets.
- [x] The public `loaf` command can dispatch Go-native `state` commands while unmigrated commands still delegate to the existing TypeScript CLI.
- [x] Build and test workflows prove the Go runtime and TypeScript compatibility bridge can coexist without exposing two public command names.
- [x] `loaf state path` prints the same path from the main worktree and linked worktrees for the same project.
Expand Down
4 changes: 2 additions & 2 deletions .agents/tasks/TASK-196-state-status-doctor-diagnostics.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,15 +30,15 @@ completed_at: '2026-05-28T17:08:01Z'

Add the approved `github.com/ncruces/go-sqlite3/driver` dependency and wire the
first real storage lifecycle commands. `loaf state init` should create the
project-scoped SQLite database outside the repository and apply Go-owned schema
global project-partitioned SQLite database outside the repository and apply Go-owned schema
migrations. `loaf state status` and `loaf state doctor` should report the
resolved project root, intended database path, DB presence, schema version, and
Markdown fallback state.

## Acceptance Criteria

- [x] `github.com/ncruces/go-sqlite3` is pinned in `go.mod`/`go.sum`.
- [x] `loaf state init` creates the project-scoped SQLite database outside the repository.
- [x] `loaf state init` creates the global project-partitioned SQLite database outside the repository.
- [x] `state init` applies the ordered Go-owned migrations and records checksums in `schema_migrations`.
- [x] `state init` is idempotent and detects migration checksum drift.
- [x] `loaf state status` prints project root, database path, database presence, mode, and schema version.
Expand Down
2 changes: 1 addition & 1 deletion .agents/tasks/TASK-234-state-init-safety-proof.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ files:
verify: >-
go test ./internal/state ./internal/cli && go test ./...
done: >-
Tests prove `loaf state init` creates a project-scoped SQLite database outside
Tests prove `loaf state init` creates a global project-partitioned SQLite database outside
the repository, prints the database path, avoids repository `.agents` writes,
and initializes a schema without secret-storage columns.
---
Expand Down
4 changes: 2 additions & 2 deletions .claude-plugin/marketplace.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,14 @@
},
"metadata": {
"description": "Loaf - An Opinionated Agentic Framework",
"version": "2.0.0-dev.49"
"version": "2.0.0-pre.20260614235428"
},
"plugins": [
{
"name": "loaf",
"description": "Loaf - An Opinionated Agentic Framework",
"source": "./plugins/loaf",
"version": "2.0.0-dev.49",
"version": "2.0.0-pre.20260614235428",
"license": "MIT",
"repository": "https://github.com/levifig/loaf"
}
Expand Down
126 changes: 126 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
name: Release

on:
push:
tags:
- 'v*'
workflow_dispatch:
inputs:
tag:
description: 'Release tag to publish, for example v2.0.0-dev.49'
required: true
update_tap:
description: 'Update levifig/homebrew-tap after uploading assets'
required: true
default: 'true'

permissions:
contents: write

jobs:
release:
runs-on: ubuntu-latest

steps:
- name: Resolve release ref
id: release
shell: bash
run: |
if [[ "${{ github.event_name }}" == "workflow_dispatch" ]]; then
tag="${{ inputs.tag }}"
else
tag="${GITHUB_REF_NAME}"
fi
if [[ -z "$tag" || "$tag" != v* ]]; then
echo "Release tag must start with v." >&2
exit 1
fi
echo "tag=$tag" >> "$GITHUB_OUTPUT"
echo "ref=refs/tags/$tag" >> "$GITHUB_OUTPUT"

- name: Checkout
uses: actions/checkout@v4
with:
ref: ${{ steps.release.outputs.ref }}

- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '22'
cache: 'npm'

- name: Setup Bun
uses: oven-sh/setup-bun@v2

- name: Setup Go
uses: actions/setup-go@v5
with:
go-version-file: go.mod

- name: Install dependencies
run: npm ci

- name: Verify release version
id: version
shell: bash
run: |
version="$(node -p "require('./package.json').version")"
expected_tag="v$version"
if [[ "${{ steps.release.outputs.tag }}" != "$expected_tag" ]]; then
echo "Tag ${{ steps.release.outputs.tag }} does not match package version $version." >&2
exit 1
fi
echo "version=$version" >> "$GITHUB_OUTPUT"

- name: Build release targets
run: npm run build:release

- name: Verify tests
run: go test ./...

- name: Package release archives
run: npm run package:release

- name: Upload release assets
env:
GH_TOKEN: ${{ github.token }}
RELEASE_TAG: ${{ steps.release.outputs.tag }}
shell: bash
run: |
if gh release view "$RELEASE_TAG" >/dev/null 2>&1; then
gh release upload "$RELEASE_TAG" dist/release/* --clobber
else
gh release create "$RELEASE_TAG" dist/release/* --title "$RELEASE_TAG" --generate-notes
fi

- name: Checkout Homebrew tap
if: ${{ github.event_name != 'workflow_dispatch' || inputs.update_tap == 'true' }}
uses: actions/checkout@v4
with:
repository: levifig/homebrew-tap
path: homebrew-tap
token: ${{ secrets.HOMEBREW_TAP_TOKEN }}

- name: Update Homebrew formula
if: ${{ github.event_name != 'workflow_dispatch' || inputs.update_tap == 'true' }}
run: |
node cli/scripts/update-homebrew-formula.mjs \
--formula homebrew-tap/Formula/loaf.rb \
--checksums dist/release/checksums.txt \
--version "${{ steps.version.outputs.version }}" \
--repo levifig/loaf

- name: Commit Homebrew tap update
if: ${{ github.event_name != 'workflow_dispatch' || inputs.update_tap == 'true' }}
working-directory: homebrew-tap
shell: bash
run: |
if git diff --quiet -- Formula/loaf.rb; then
echo "Homebrew formula already current."
exit 0
fi
git config user.name "github-actions[bot]"
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
git add Formula/loaf.rb
git commit -m "chore: update loaf to ${{ steps.version.outputs.version }}"
git push
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ dist-cli/
# Temporary backups
dist-backup/
plugins-backup/
dist/release/

# OS files
.DS_Store
Expand Down
Loading
Loading