Files
tai/taicpp/docs/wiring/foundation.md
T
retoorandClaude Sonnet 5.5 4583265122 taicpp foundation: vault, settings, debug log, sessions keyed by shell/pane, REPL, plexer
Full port of the Store (17 tables, FTS5, per-profile slices, sessions, turn state,
bots, settings, MCP registry), DebugLog, SETTINGS_CATALOG and boot_settings,
ShellSession (as ShellContext), Conversation persistence, Repl/Boot, and the
PlexerController family with FlowValidator/PlexerFlow. Verified by replaying 643
operations through tai.py and the C++ code (results, tables, FTS, schema, files
identical) and by restarting the REPL under per-pane shells and checking the vault.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-25 02:02:31 +02:00

5.7 KiB

Wiring: foundation (for the integrator)

Everything below is applied outside the foundation directories. The foundation area edited none of main.cpp, src/cli, Makefile, PARITY.md.

1. Makefile

ALL_SRCS already picks up every src/**/*.cpp (store, session, config, plexer, repl). Needed changes:

  • Link line ($(BIN), detz_test, static): -lsqlite3 is enough; nothing else new. -pthread is not required by the foundation code.

  • Replace the stale rule

    $(BUILD)/store_test: tests/store_test.cpp src/store/store.cpp
        ... tests/store_test.cpp src/store/store.cpp -lsqlite3 -lcurl -o $@
    

    by $(BUILD)/store_test: tests/store_test.cpp $(ALL_SRCS) compiled like detz_test (the new Store needs the other store, session and config sources).

  • Test target: add include tests/foundation.mk (or call $(MAKE) -f tests/foundation.mk test from make test). It builds build/foundation_probe, build/repl_probe, build/foundation_test and runs the three suites.

  • plexer.mk still says SRCS += src/plexer/plexer.cpp; the other *.mk files are not used by the Makefile.

2. main.cpp (REPL, one-shot, debug, profile, --continue)

#include "repl/boot.h"
#include "repl/repl.h"
...
auto& o = cmd.opts;
detz::repl::Boot::configure_debug(o.debug, o.debug_format);                 // before anything else
if (!detz::repl::Boot::valid_profile(o.profile.value_or(o.telegram ? "telegram" : "default"))) return 1;
detz::repl::BootOptions boot;
boot.profile = o.profile.value_or(o.telegram ? "telegram" : "default");
boot.yes = o.yes; boot.yolo = o.yolo; boot.autonomous = o.auto_; boot.no_opencode = o.no_opencode;
boot.version = detz::kVersion;
boot.mode = !o.prompt.empty() ? "one-shot" : "repl";
boot.seal_factory = ...;            // adapter from the Seal owner, see section 4
boot.catalogs = {skill_catalog, tool_catalog, scope_changed, profile_reset};   // agent module hooks
std::unique_ptr<detz::repl::BootedSession> app;
try { app = detz::repl::Boot::open(boot); }
catch (const detz::store::SealError& e) { std::fprintf(stderr, "seal error: %s\n", e.what()); return 2; }
MyAgentHost host(*app->conversation, ...);          // implements detz::repl::ReplHost, appends messages to app->conversation
detz::repl::Repl::Options ro; ro.version = detz::kVersion; ro.resume = o.resume; ro.telegram = o.telegram; ro.scheduler = o.scheduler;
detz::repl::Repl repl(*app->conversation, host, ro);
if (!o.prompt.empty()) return repl.oneshot(join(o.prompt, " "));   // exit codes 0, 1, 130 as tai.py
return repl.run();

Per-step order is tai.py main: debug sink, --version etc., then boot, then --env, --eval-retrieval, --stats-rag, --scheduler, --telegram, --tui-local, prompt, REPL. Boot::open prints vault schema upgraded: ... and settings from vault: ... like python. Repl::run and Repl::oneshot close the store.

--plexer-wrap and --mplex are not foundation code; plexer::PlexerControllerFactory::detect() is what the plexer tools call.

3. Agent module hooks

  • Implement detz::repl::ReplHost (src/repl/repl_host.h): run_turn must call conversation.begin_turn(goal), append user/assistant/tool messages with conversation.add_message (or push Json into conversation.messages()), call note_step()/note_tool() while working, and close_turn() at the end (the equivalent of Agent.run_turn). Throw repl::TurnInterrupted (or poll repl::Interrupt::requested()) on Ctrl-C.

  • Conversation::switch_profile/switch_bot call Catalogs::profile_reset (clear read files and secret grants) and scope_changed (chat.scope = (profile, bot)).

  • session::DirDefaults::apply(conversation, hooks) replaces apply_dir_defaults; call it after Boot::open and print the returned line dimmed when non-empty.

  • Record tools in src/agent/exec.cpp use the removed stub API. Replace (python names, ids are mem:<16 hex> strings):

    auto st = detz::store::Store::Open(workdir + "/detz.db");
    record_save   : std::string id = st->add_record(kind, title, content);               return ok(id);
    record_read   : auto r = st->get_record(id);  if (!r) return err("not found");       return ok(r->get_string("content"));
    record_search : for (auto& r : st->search_records(query)) ...                         (fields id, kind, title, size, reads, updated, tags)
    search        : for (auto& h : st->fts_search(query)) ...                             (fields item, kind, sub, title, snippet, rank)
    record_delete : return ok(st->delete_record(id) ? "deleted" : "not found");
    

    In the real app the tools should share the booted Store (*app->store) and the current profile instead of opening detz.db.

  • Large tool output: detz::store::Spill::spill_or_truncate(&store, kind, title, text).

  • Debug events: detz::store::DebugLog::Global().event(level, component, event, message, profile, bot, chat, meta); no-op while disabled.

4. Seal

src/seal is outside this area. Provide a class deriving detz::store::SealPort (enabled, default_key, lock, unlock; prefix tai1$) and return it from BootOptions::seal_factory(home, passphrase, default_key). The factory also owns the python behaviours not ported here: .seal file handling, rotate_seal and the default-key to TAI_PASSPHRASE upgrade. Until then the vault is plain text when TAI_PASSPHRASE is unset and Boot::open refuses an explicit passphrase.

5. CLI facts the foundation relies on

src/cli/cli.h Options already has profile, debug, debug_format, resume, yes, yolo, auto_, no_opencode, telegram, scheduler, prompt. No change needed.

6. PARITY.md / CHANGELOG

Symbols covered are listed in docs/foundation.md ("Symbol map"); the foundation area did not touch PARITY.md or CHANGELOG.md.