{"record":{"id":"58285080af7d9524","repo":"sipeed/picoclaw","slug":"seahorse-create-engine-w","errorCode":null,"errorMessage":"seahorse: create engine: %w","messagePattern":"seahorse: create engine: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/agent/context_seahorse.go","lineNumber":45,"sourceCode":"func newSeahorseContextManager(_ json.RawMessage, al *AgentLoop) (ContextManager, error) {\n\tif al == nil {\n\t\treturn nil, fmt.Errorf(\"seahorse: AgentLoop is required\")\n\t}\n\n\t// Resolve workspace for DB path\n\t// DB stores session data, so it goes in sessions/ directory\n\tagent := al.registry.GetDefaultAgent()\n\tdbPath := agent.Workspace + \"/sessions/seahorse.db\"\n\n\t// Create CompleteFn from provider\n\tcompleteFn := providerToCompleteFn(agent.Provider, agent.Model)\n\n\t// Create engine\n\tengine, err := seahorse.NewEngine(seahorse.Config{\n\t\tDBPath: dbPath,\n\t}, completeFn)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"seahorse: create engine: %w\", err)\n\t}\n\n\tmgr := &seahorseContextManager{\n\t\tengine:   engine,\n\t\tsessions: agent.Sessions,\n\t\tal:       al,\n\t}\n\n\t// Register seahorse tools with the agent's tool registry\n\tretrieval := mgr.engine.GetRetrieval()\n\tal.RegisterTool(seahorse.NewGrepTool(retrieval))\n\tal.RegisterTool(seahorse.NewExpandTool(retrieval))\n\n\t// Bootstrap all existing sessions at startup\n\tif agent.Sessions != nil {\n\t\tctx := context.Background()\n\t\tfor _, sessionKey := range agent.Sessions.ListSessions() {\n\t\t\tmgr.bootstrapSession(ctx, sessionKey)","sourceCodeStart":27,"sourceCodeEnd":63,"githubUrl":"https://github.com/sipeed/picoclaw/blob/49183d7e8daed0dba89ddbb6fcb60089401d9680/pkg/agent/context_seahorse.go#L27-L63","documentation":"When agents.defaults.context_manager is \"seahorse\", picoclaw builds a seahorse engine backed by a SQLite database at <default-agent-workspace>/sessions/seahorse.db (seahorse.NewEngine). Any failure creating/opening that DB is wrapped here. In the standard resolveContextManager path this failure is logged and picoclaw falls back to the legacy context manager, so the impact is losing seahorse retrieval, not a crash.","triggerScenarios":"context_manager=seahorse selected and the SQLite DB cannot be created or opened: sessions/ directory missing or not writable under the workspace, disk full, seahorse.db corrupt, or the file locked by another picoclaw process sharing the workspace.","commonSituations":"Workspace on a read-only volume (containers); two instances pointed at one workspace; partially copied workspace with a corrupt seahorse.db; restrictive fs permissions or SELinux denials under ~/.picoclaw/workspace.","solutions":["Read the wrapped error to classify: permission vs corrupt vs database-is-locked","mkdir -p <workspace>/sessions and fix ownership/permissions (writable by the picoclaw user)","Give each picoclaw process its own workspace, or stop the second instance holding the SQLite lock","Rename or delete a corrupt seahorse.db so it is rebuilt (context cache lost; JSONL session history is separate)","Confirm the platform is supported — seahorse is compiled out on mipsle/netbsd/freebsd-arm"],"exampleFix":"# before — workspace/sessions missing or read-only\nls -ld workspace/sessions  # missing or 0555\n\n# after\nmkdir -p workspace/sessions && chmod 755 workspace/sessions && chown picoclaw: workspace/sessions","handlingStrategy":"try-catch","validationCode":"agent := al.GetRegistry().GetDefaultAgent()\ndir := filepath.Join(agent.Workspace, \"sessions\")\nif err := os.MkdirAll(dir, 0o755); err != nil {\n    return fmt.Errorf(\"prepare seahorse dir: %w\", err)\n}\nprobe, err := os.OpenFile(filepath.Join(dir, \"seahorse.db\"), os.O_RDWR|os.O_CREATE, 0o644)\nif err != nil {\n    return fmt.Errorf(\"seahorse.db not writable: %w\", err)\n}\nprobe.Close()","typeGuard":null,"tryCatchPattern":"cm, err := seahorse.NewEngine(seahorse.Config{DBPath: dbPath}, completeFn)\nif err != nil {\n    // log and degrade: keep running with the legacy context manager\n    log.Printf(\"seahorse unavailable (%v); falling back to legacy context\", err)\n    return &legacyContextManager{al: al}, nil\n}","preventionTips":["Pre-create <workspace>/sessions and verify write access in the container image/unit file","Run one picoclaw process per workspace to avoid SQLite lock contention","Monitor startup logs for the 'falling back to legacy' warning — the downgrade is silent otherwise"],"tags":["go","picoclaw","seahorse","sqlite","context-manager","filesystem"],"backgroundTag":null,"analyzedSha":"49183d7e8daed0dba89ddbb6fcb60089401d9680","analyzedAt":"2026-08-15T21:55:41.315Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}