Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 0 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -518,8 +518,6 @@ sdd show d-cpt-vr4 # the entry plus its grounding and consumers
sdd show d-cpt-vr4 --up 4 --down 3 # widen the neighborhood
```

**`sdd recover`** — inspect a durable write whose outcome needs an explicit decision. The interactive command reconciles the concrete branch target before offering a valid action; it never replays pending work automatically. `sdd recover --history` shows terminal audit history. See [local mutation targets and recovery](docs/local-mutation-recovery.md).

For the full CLI surface, run `sdd --help`.

## Directory layout
Expand Down Expand Up @@ -549,7 +547,6 @@ Registering the MCP server does land in your project tree, so engine mode works
- [docs/signal-dialogue-decision.md](docs/signal-dialogue-decision.md) — framework model
- [docs/story.md](docs/story.md) — a fictional story (Kōgen Coffee) of what SDD could become; the vision that sparked the design
- [docs/signals.md](docs/signals.md) — open design signals for the framework itself
- [docs/local-mutation-recovery.md](docs/local-mutation-recovery.md) — explicit branch authority, durable apply, and recovery states
- [CLAUDE.md](CLAUDE.md) — guidance for Claude Code working on SDD itself

## Star the repo
Expand Down
55 changes: 0 additions & 55 deletions docs/local-mutation-recovery.md

This file was deleted.

6 changes: 0 additions & 6 deletions examples/extendingsdd/adapters_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,6 @@ import (
type graphStore struct{}

func (graphStore) Current(context.Context) (*sdd.Snapshot, error) { return &sdd.Snapshot{}, nil }
func (graphStore) Apply(context.Context, string, sdd.MutationBatch, sdd.StagedBlobReader) (sdd.ApplyResult, error) {
return sdd.ApplyResult{State: sdd.MutationApplied, Revision: "r2"}, nil
}
func (graphStore) Reconcile(context.Context, string, string) (sdd.ApplyResult, error) {
return sdd.ApplyResult{State: sdd.MutationApplied, Revision: "r2"}, nil
}
func (graphStore) ReadAttachmentPage(context.Context, string, string, int64, int) (sdd.AttachmentPage, error) {
return sdd.AttachmentPage{}, nil
}
Expand Down
10 changes: 5 additions & 5 deletions internal/baseprocedures/entries/20260703-194500-d-prc-cat.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,11 @@ state:
steps:
- id: compose
inject:
- {id: focus, fn: viewLayout, args: {layout: 'focus:brief', recovery: false}, maxBytes: 4000}
- {id: recentDone, fn: viewLayout, args: {layout: 'kind(done):rank(by(date)):n(10):name("Recent done"):brief:as-list', recovery: false}, maxBytes: 4000}
- {id: activeHot, fn: viewLayout, args: {layout: 'kind(plan,activity,directive):active:not(intent(guiding)):rank(heat(exp-7d)):n(8):expand(refs(inactive)):name("Active and hot"):brief:as-list', recovery: false}, maxBytes: 6000}
- {id: openLoops, fn: viewLayout, args: {layout: 'kind(plan,activity,directive,gap,question):active:not(intent(guiding)):rank(coldness(exp-30d)):n(8):expand(refs):name("Open loops"):brief:as-list', recovery: false}, maxBytes: 6000}
- {id: openWarm, fn: viewLayout, args: {layout: 'kind(gap,question,insight):active:rank(heat(exp-14d)):n(15):name("Open and warm"):brief:as-list', recovery: false}, maxBytes: 5000}
- {id: focus, fn: viewLayout, args: {layout: 'focus:brief'}, maxBytes: 4000}
- {id: recentDone, fn: viewLayout, args: {layout: 'kind(done):rank(by(date)):n(10):name("Recent done"):brief:as-list'}, maxBytes: 4000}
- {id: activeHot, fn: viewLayout, args: {layout: 'kind(plan,activity,directive):active:not(intent(guiding)):rank(heat(exp-7d)):n(8):expand(refs(inactive)):name("Active and hot"):brief:as-list'}, maxBytes: 6000}
- {id: openLoops, fn: viewLayout, args: {layout: 'kind(plan,activity,directive,gap,question):active:not(intent(guiding)):rank(coldness(exp-30d)):n(8):expand(refs):name("Open loops"):brief:as-list'}, maxBytes: 6000}
- {id: openWarm, fn: viewLayout, args: {layout: 'kind(gap,question,insight):active:rank(heat(exp-14d)):n(15):name("Open and warm"):brief:as-list'}, maxBytes: 5000}
- {id: wip, fn: viewLayout, args: {layout: 'wip'}, maxBytes: 2000}
collect: [briefing]
transitions:
Expand Down
12 changes: 6 additions & 6 deletions internal/baseprocedures/entries/20260704-100000-d-prc-dlg.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,12 @@ steps:
transitions:
- to: end(completed)
framing:
- {id: principles, fn: viewLayout, args: {layout: 'active:kind(fact):topic("principles/interactive"):as-bodies:name("Working principles")', recovery: false}}
- {id: aspirations, fn: viewLayout, args: {layout: 'aspirations:rank(heat(exp-14d)):n(8):brief', recovery: false}}
- {id: directives, fn: viewLayout, args: {layout: 'kind(directive):intent(guiding):active:rank(heat(exp-14d)):n(10):name("Guiding directives"):brief:as-list', recovery: false}}
- {id: focus, fn: viewLayout, args: {layout: 'focus:brief', recovery: false}}
- {id: participants, fn: viewLayout, args: {layout: 'participants:brief', recovery: false}}
- {id: recentMovement, fn: viewLayout, args: {layout: 'rank(by(date)):n(10):brief:as-list:name("Recent graph movement")', recovery: false}, maxBytes: 2500}
- {id: principles, fn: viewLayout, args: {layout: 'active:kind(fact):topic("principles/interactive"):as-bodies:name("Working principles")'}}
- {id: aspirations, fn: viewLayout, args: {layout: 'aspirations:rank(heat(exp-14d)):n(8):brief'}}
- {id: directives, fn: viewLayout, args: {layout: 'kind(directive):intent(guiding):active:rank(heat(exp-14d)):n(10):name("Guiding directives"):brief:as-list'}}
- {id: focus, fn: viewLayout, args: {layout: 'focus:brief'}}
- {id: participants, fn: viewLayout, args: {layout: 'participants:brief'}}
- {id: recentMovement, fn: viewLayout, args: {layout: 'rank(by(date)):n(10):brief:as-list:name("Recent graph movement")'}, maxBytes: 2500}
---

The user-dialogue shell is the base procedure a session opens with: one long-lived instance whose pending junction is where free dialogue happens, whose serves are where every move lands when it ends, and whose conclude path is the deliberate way out. The agent is never goalless — before the first move, between moves, and after the last one, this instance's serve names where the dialogue stands.
Expand Down
1 change: 0 additions & 1 deletion internal/cliapp/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -392,7 +392,6 @@ func New(options Options) *cli.Command {
searchCmd(),
serveCmd(),
sessionsCmd(),
recoverCmd(),
syncCmd(),
repoCmd(),
statsCmd(),
Expand Down
79 changes: 79 additions & 0 deletions internal/cliapp/local_store_application.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
package cliapp

import (
"context"
"fmt"
"path/filepath"

"github.com/urfave/cli/v3"

"github.com/networkteam/sdd/internal/repos"
sdd "github.com/networkteam/sdd/pkg/application"
pkgllm "github.com/networkteam/sdd/pkg/llm"
localadapter "github.com/networkteam/sdd/pkg/local"
)

// buildLocalStoreApplication composes the application over the local checkout
// for commands that inspect session state without running language models.
func buildLocalStoreApplication(ctx context.Context, cmd *cli.Command) (*sdd.Application, sdd.ProjectID, sdd.RequestIdentity, error) {
graphDir, err := resolveGraphDir(cmd)
if err != nil {
return nil, "", sdd.RequestIdentity{}, err
}
sddDir, err := resolveSDDDir()
if err != nil {
return nil, "", sdd.RequestIdentity{}, err
}
cfg, err := loadConfig()
if err != nil {
return nil, "", sdd.RequestIdentity{}, err
}
if cfg == nil || cfg.DefaultBranch == "" {
return nil, "", sdd.RequestIdentity{}, fmt.Errorf("default_branch is required in .sdd/config.yaml")
}
locations, err := repos.DefaultLocations()
if err != nil {
return nil, "", sdd.RequestIdentity{}, err
}
storeLocations, err := resolveSessionLocations(sddDir, cfg, locations)
if err != nil {
return nil, "", sdd.RequestIdentity{}, err
}
project := sessionStoreProject(cfg)
graph, err := localadapter.NewFilesystemGraphStore(localadapter.FilesystemGraphStoreOptions{Project: project, GraphDir: graphDir})
if err != nil {
return nil, "", sdd.RequestIdentity{}, err
}
sessions, err := localadapter.NewFilesystemSessionStore(storeLocations...)
if err != nil {
return nil, "", sdd.RequestIdentity{}, err
}
blobs, err := localadapter.NewFilesystemStagedBlobStore(storeLocations...)
if err != nil {
return nil, "", sdd.RequestIdentity{}, err
}
targets, err := localadapter.NewRepositoryTargets(project, filepath.Dir(sddDir), locations.ConfigPath)
if err != nil {
return nil, "", sdd.RequestIdentity{}, err
}
runtime, err := sdd.NewProjectRuntime(sdd.ProjectRuntimeOptions{
Project: sdd.ProjectRef{ID: project, DisplayName: filepath.Base(filepath.Dir(sddDir))}, DefaultBranch: cfg.DefaultBranch,
Graph: graph, Targets: targets,
LLM: pkgllm.RunnerFunc(func(context.Context, pkgllm.Request) (pkgllm.Result, error) {
return pkgllm.Result{}, fmt.Errorf("session inspection does not execute language models")
}),
})
if err != nil {
return nil, "", sdd.RequestIdentity{}, err
}
access := &localRuntimeAccess{project: project, participant: cfg.Participant, runtime: runtime, dependencies: map[string]*sdd.ProjectRuntime{}}
application, err := sdd.NewApplication(sdd.ApplicationOptions{Access: access, Sessions: sessions, StagedBlobs: blobs})
if err != nil {
return nil, "", sdd.RequestIdentity{}, err
}
identity := sdd.RequestIdentity{Subject: "local"}
if _, err := application.Info(ctx, identity, project, sdd.InfoRequest{}); err != nil {
return nil, "", sdd.RequestIdentity{}, err
}
return application, project, identity, nil
}
Loading
Loading