Documentation
¶
Overview ¶
Package install wires a vault into the machine: it writes the per-vault contracts (.hebb/config.toml, the project-scoped .mcp.json), symlinks global skills and memory, and renders launchd jobs. Every operation is idempotent and parameterised by its target directories so it is fully testable and never hard-codes a home directory.
Index ¶
- Constants
- func AnyFailed(checks []Check) bool
- func AnyRemoved(r TeardownReport) bool
- func AssetName(version, goos, goarch string) string
- func BinaryFromArchive(targz []byte) ([]byte, error)
- func Bootout(label string)
- func Bootstrap(plistPaths []string, run bool) ([]string, error)
- func ClaudeProjectSlug(absPath string) string
- func ClaudeSkillsDir(home string) string
- func CodexSkillsDir(home string) string
- func DefaultClaudeDesktopConfigPath(home string) string
- func GlobalWebJob(hebbBin, home string) launchd.Job
- func InstallSkills(skillsFS fs.FS, dir string) ([]string, error)
- func MCPToolNames() []string
- func MaterializeAssets(fsys fs.FS, dataDir string) (int, error)
- func MemoryDir(vaultPath string) string
- func NewerAvailable(current, latest string) bool
- func ParseVersion(s string) (maj, min, patch int, ok bool)
- func PythonPath() string
- func RemoveClaudeDesktopConfig(configPath, name string) (string, error)
- func RemoveCodexConfig(configPath, name string) (string, error)
- func RenderBootstrap(version string, trackLatest bool) []byte
- func RenderCodexServer(name, command, vaultPath string) string
- func RenderMCPJSON(serverName, command string) ([]byte, error)
- func ReplaceBinary(path string, data []byte) error
- func RestartServices() ([]string, error)
- func Slugify(s string) string
- func StableBinPath(exePath string, candidates []string) string
- func StableHebbBin(exePath string) string
- func SymlinkMemory(vaultPath, claudeProjectsDir, projectSlug string) (string, error)
- func UpdateManagedSkills(skillsFS fs.FS, dir string) ([]string, error)
- func VaultJobs(vaultPath, slug, hebbBin, assetRoot, home string, port int, names []string, ...) []launchd.Job
- func VerifyChecksum(data []byte, checksums, assetName string) error
- func WriteBootstrap(vaultPath, version string, trackLatest bool) (bool, error)
- func WriteClaudeDesktopConfig(configPath, name, command, vaultPath string) (string, error)
- func WriteCodexConfig(configPath, name, command, vaultPath string) (string, error)
- func WriteMCPJSON(vaultPath, serverName, command string) (bool, error)
- func WriteProjectSettings(vaultPath, serverName string) (bool, error)
- type Check
- type InstallMethod
- type Options
- type Report
- type Step
- type TeardownOptions
- type TeardownReport
- type TeardownStep
- type Updater
Constants ¶
const DefaultCodexStartupTimeoutSec = 20
DefaultCodexStartupTimeoutSec gives the pure-Go SQLite index time to open on a cold first run, above Codex's 10s default.
const DefaultMCPCommand = "hebb"
DefaultMCPCommand is the binary Claude launches for the MCP server. It is a bare name resolved on PATH (brew/npm install) rather than an absolute path, so the committed .mcp.json travels with a synced vault.
const DefaultMCPServerName = "hebb"
DefaultMCPServerName is the server key written into .mcp.json (and so the tool prefix Claude sees, e.g. mcp__hebb__search_vault).
const DefaultRepo = "cizer/hebb"
DefaultRepo is the GitHub repo hebb releases come from.
const GlobalWebLabel = "local.hebb.web"
GlobalWebLabel is the launchd label of the one machine-global web service. It has no vault slug (unlike per-vault jobs), so per-vault teardown never touches it.
const GlobalWebPort = 4321
GlobalWebPort is the port the single machine-global web service binds.
Variables ¶
This section is empty.
Functions ¶
func AnyRemoved ¶
func AnyRemoved(r TeardownReport) bool
AnyRemoved reports whether the report contains an action that removed (or would remove) something - useful for exit codes / messaging.
func AssetName ¶
AssetName is the release asset for a version/platform, matching GoReleaser and install.sh (e.g. hebb_0.1.1_darwin_arm64.tar.gz).
func BinaryFromArchive ¶
BinaryFromArchive extracts the file named "hebb" from a .tar.gz release asset.
func Bootout ¶
func Bootout(label string)
Bootout unloads a launchd job from the user's domain, best-effort: a job that is not loaded (or a machine without launchctl, e.g. Linux/CI) is fine.
func Bootstrap ¶
Bootstrap (re)loads the given plists into the user's launchd domain. When run is false it returns the commands it would execute without running them, so an install can preview the bootstrap. A failed bootout (the job was not loaded) is ignored; only bootstrap failures are returned as errors.
func ClaudeProjectSlug ¶
ClaudeProjectSlug reproduces Claude Code's per-project directory naming: every non-alphanumeric character in the absolute path becomes '-', with case preserved and no collapsing. So /Users/a.b/v becomes -Users-a-b-v.
func ClaudeSkillsDir ¶ added in v0.3.0
ClaudeSkillsDir is Claude Code's user-global (personal) skills directory.
func CodexSkillsDir ¶ added in v0.3.0
CodexSkillsDir is Codex's user-global skills directory.
func DefaultClaudeDesktopConfigPath ¶
DefaultClaudeDesktopConfigPath is the macOS location of the Claude Desktop config under the given home dir.
func GlobalWebJob ¶ added in v0.5.0
GlobalWebJob is the single machine-global web service: one `hebb serve` (no --vault) that serves every registered vault on one loopback port, switchable in the UI. It replaces the per-vault web jobs, which all defaulted to the same port and collided.
func InstallSkills ¶ added in v0.3.0
InstallSkills materialises the bundled skills (skillsFS rooted at the skills parent, each immediate subdirectory a skill with a SKILL.md) into dir. hebb owns the skills it ships: it writes and updates their files and leaves any other skill already in dir untouched. Unchanged files are skipped, so it is idempotent and cheap to re-run (e.g. after `hebb update`). Returns the names of the skills delivered.
func MCPToolNames ¶
func MCPToolNames() []string
MCPToolNames are the tools the hebb MCP server exposes. They must match the tool names registered in package mcp.
func MaterializeAssets ¶
MaterializeAssets writes the embedded function assets (fsys) onto disk under dataDir, preserving the tree. It is idempotent (unchanged files are skipped) and returns the number of files written or updated. Files under automation/ are made executable, since go:embed does not preserve the executable bit.
func MemoryDir ¶
MemoryDir is the in-vault home for this vault's Claude Code memory. It lives under .hebb so agent memory still syncs and travels with the vault, but is hidden from Obsidian (a dotfolder) and excluded from the index (.hebb is in the default exclude list), so memory is never treated as vault content.
func NewerAvailable ¶
NewerAvailable reports whether latest is a strictly higher release than current. A dev build (version containing "dev") or any unparseable version returns false, so a dev binary is never auto-replaced by a release.
func ParseVersion ¶
ParseVersion parses vMAJOR.MINOR.PATCH (leading v optional; any pre-release or build suffix is ignored). ok is false for non-release strings (e.g. a dev build like "0.0.0-dev (abc123)"), so callers can refuse to compare them.
func PythonPath ¶ added in v0.4.0
func PythonPath() string
PythonPath resolves an absolute python3 (launchd has a minimal PATH), falling back to the bare name if it cannot be located. Exported so `hebb digest` can resolve the interpreter the same way the rendered launchd jobs do.
func RemoveClaudeDesktopConfig ¶
RemoveClaudeDesktopConfig deletes the mcpServers.<name> entry, preserving every other server and key. Returns "removed" or "absent".
func RemoveCodexConfig ¶
RemoveCodexConfig deletes the [mcp_servers.<name>] block from the Codex config at configPath, preserving every other server, comment, and key. Returns "removed" if a block was deleted, or "absent" if there was no config or no matching block. The inverse of WriteCodexConfig, used by `hebb reset`.
func RenderBootstrap ¶ added in v0.5.0
RenderBootstrap returns the bootstrap.sh contents. By default it pins the hebb version when version is a clean release (so a clone gets a binary new enough to open the vault's index); a dev or unknown version leaves the pin off so install.sh fetches the latest release. When trackLatest is true it pins to "latest" so a clone always installs the newest release (config [bootstrap] track_latest).
func RenderCodexServer ¶
RenderCodexServer returns the TOML block for a [mcp_servers.<name>] stdio entry pinned to vaultPath. env is an inline table so the whole entry is one contiguous block (no trailing sub-table a merge could orphan).
func RenderMCPJSON ¶
RenderMCPJSON returns the canonical project-scoped .mcp.json for a vault. args is just ["mcp"]: hebb resolves the vault from the directory it is launched in (the vault root, where this file lives), keeping the committed file free of machine-specific absolute paths.
func ReplaceBinary ¶
ReplaceBinary atomically replaces the file at path with data: it writes a temp file in the same directory, makes it executable, and renames it over the target. Replacing the path of a running binary is safe on Unix (the running process keeps the old inode).
func RestartServices ¶ added in v0.5.0
RestartServices restarts every loaded hebb web service across all vaults on this machine via `launchctl kickstart -k` (kill and relaunch), so a replaced binary takes effect. Only the long-running web jobs are restarted; scheduled jobs pick up the new binary on their next run. It is a safe no-op (returns nil, nil) where launchctl is unavailable (e.g. Linux), so callers can invoke it unconditionally. Returns the labels restarted.
func Slugify ¶
Slugify turns a vault name into a label-safe token (lowercase, alphanumerics and single hyphens), used in launchd labels and the memory symlink path.
func StableBinPath ¶ added in v0.4.0
StableBinPath is the testable core of StableHebbBin: given the executable path and a list of candidate stable symlinks, it returns a candidate that resolves to the same binary as exePath when exePath sits under a versioned Cellar dir, else exePath. Only Cellar paths are rewritten, because only they churn across upgrades; a self-managed or go-install binary is left alone even if a symlink happens to point at it.
func StableHebbBin ¶ added in v0.4.0
StableHebbBin returns the binary path to embed in launchd jobs for the running hebb executable. When exePath resolves into a versioned Homebrew Cellar dir (so the path churns on every upgrade and the TCC Full Disk Access grant would reset), it prefers a stable symlink such as /opt/homebrew/bin/hebb that resolves to the same binary. Otherwise it returns exePath unchanged.
func SymlinkMemory ¶
SymlinkMemory links <vault>/.hebb/memory into <claudeProjectsDir>/<projectSlug>/memory so Claude Code reads the vault's (synced) memory when opened there. The vault memory dir is created if absent. It is defensive: an existing real memory dir at the target is left untouched (status "conflict").
func UpdateManagedSkills ¶ added in v0.3.0
UpdateManagedSkills re-applies the bundled skills to dir, but only if hebb already manages skills there (at least one bundled skill is present). When the dir is managed it installs the full bundle, so a new skill in a release is deployed and changed skills are refreshed; when it is not (an agent the user doesn't use, or one they installed with --no-skills) it does nothing, so an upgrade never forces skills onto an opted-out dir. Returns the skills applied.
func VaultJobs ¶
func VaultJobs(vaultPath, slug, hebbBin, assetRoot, home string, port int, names []string, updateAuto bool, jobArgs map[string][]string, jobEnv map[string]map[string]string) []launchd.Job
VaultJobs builds launchd job specs for the named jobs of a vault. The web, update-check and daily-digest jobs are built in (they run the hebb binary; `hebb digest` no longer needs a materialised script). The action-review job is only included when its script exists under <assetRoot>/automation, so no broken plist is written if the automation script is absent. updateAuto makes the update-check job install updates rather than only reporting them. jobArgs carries the per-job extra arguments from config.toml's [job_args]; they are appended to the matching job's program. jobEnv carries per-job extra environment variables from config.toml's [job_env]; they are merged into the job's EnvVars after built-in env, with user-supplied keys overriding built-in keys of the same name (user wins). The merge produces a deterministic slice: built-in env order is preserved for unoverridden keys, then user-supplied extra keys sorted alphabetically. Unknown job names are skipped.
func VerifyChecksum ¶
VerifyChecksum checks the sha256 of data against the entry for assetName in a GoReleaser checksums.txt body (lines of "<hex> <name>").
func WriteBootstrap ¶ added in v0.5.0
WriteBootstrap writes bootstrap.sh (executable) at the vault root. Idempotent: it rewrites only when the contents differ, so the version pin tracks the hebb that last installed the vault. Returns true if the file was created or changed.
func WriteClaudeDesktopConfig ¶
WriteClaudeDesktopConfig merges an mcpServers.<name> entry (pinned to vaultPath via HEBB_VAULT) into the Claude Desktop config, creating it if absent. Other servers and top-level keys are preserved. Idempotent; returns "wrote", "updated", or "unchanged".
func WriteCodexConfig ¶
WriteCodexConfig merges the hebb server block into the Codex config at configPath, creating the file (and parent dir) if absent. It is idempotent and non-destructive. Returns "created", "updated", or "unchanged".
func WriteMCPJSON ¶
WriteMCPJSON writes .mcp.json at the vault root, idempotently. It returns true if the file was created or its contents changed.
func WriteProjectSettings ¶
WriteProjectSettings merges hebb's MCP wiring into <vault>/.claude/settings.json: it enables the project-scoped MCP server and pre-approves its tools so the agent is not prompted for each call. Any existing settings are preserved; only the relevant arrays are extended. Returns true if the file was created or changed.
Types ¶
type InstallMethod ¶
type InstallMethod int
InstallMethod is how the running binary was installed, which decides whether `hebb update` may self-replace it.
const ( SelfManaged InstallMethod = iota // hebb owns the binary (e.g. install.sh) Homebrew // managed by `brew upgrade` GoInstall // managed by `go install ...@latest` )
func DetectInstallMethod ¶
func DetectInstallMethod(exePath string) InstallMethod
DetectInstallMethod classifies the binary at exePath (symlinks resolved).
func (InstallMethod) AdviseCommand ¶
func (m InstallMethod) AdviseCommand() string
AdviseCommand returns the command a user should run to update a binary hebb does not own, or "" when hebb may self-replace.
func (InstallMethod) String ¶
func (m InstallMethod) String() string
type Options ¶
type Options struct {
VaultPath string
MCPName string
MCPCommand string
Home string // base dir containing .claude (e.g. ~); "" disables memory wiring
HebbBin string // path to the hebb binary, for the web launchd job
LaunchdDir string // target LaunchAgents dir; "" disables launchd rendering
Load bool // if true, bootstrap rendered jobs via launchctl
MCPJSON bool // if true, write a per-vault .mcp.json + settings (plugin-less wiring)
SkipSkills bool // if true, do not install agent skills into ~/.claude/skills
// RegistryPath is the machine-global vault registry to register this vault
// in (so one web server can enumerate it). Empty skips registration.
RegistryPath string
// HebbVersion is stamped into the committed bootstrap.sh as the pinned
// release for clones to install (empty / dev leaves it unpinned -> latest).
HebbVersion string
// Agent config paths, used only by Doctor to re-verify wiring drift
// read-only. Empty means "use the conventional default under Home"; when
// that default file is absent the check stays silent (never-wired is silent).
CodexConfig string // Codex config.toml (default: <home>/.codex/config.toml)
ClaudeDesktopConfig string // Claude Desktop config (default: macOS app support dir)
// Asset source. The binary is standalone: Assets carries the embedded
// function content (automation/, vault-template/), materialised to DataDir on
// install so launchd jobs can find their scripts. AssetRoot is a development
// override - point it at a repo checkout to use its automation/ straight from
// source and skip materialisation.
Assets fs.FS
DataDir string
AssetRoot string
}
Options configures an install run. Directory fields are explicit so install is fully testable and never hard-codes a home directory. An empty Home disables the home-side wiring (vault-local steps still run).
type Report ¶
type Report struct {
Steps []Step
}
Report is the ordered list of actions an install performed.
func Run ¶
Run performs the file-level install for a vault and returns a report of every action. It does not build the index (the caller owns the engine/db). Steps:
- vault config: .hebb/config.toml (always)
- plugin-less wiring (if MCPJSON): .mcp.json + <vault>/.claude/settings.json (the hebb plugin normally provides the MCP server instead)
- assets: materialise embedded automation scripts to DataDir (unless --asset-root points at a live repo checkout), for launchd jobs
- memory (if Home): symlink <vault>/.hebb/memory into the Claude project dir
- launchd (if requested): render the vault's jobs
Skills are delivered by the hebb Claude Code plugin (see plugin/), not by install. Every step is idempotent.
func Scaffold ¶
Scaffold materialises the vault template tree (tmpl) into vaultPath, creating the directory if needed. It is defensive: it refuses to scaffold into a directory that already has contents, so it never clobbers an existing vault. An absent or empty target is fine. Returns a report of the action.
tmpl is the template filesystem rooted at its contents (e.g. the embedded assets sub-FS for "vault-template", or os.DirFS of a checkout's vault-template/). The per-vault contracts (.hebb/config.toml, .mcp.json) are not part of the template; install writes those afterwards.
func VaultLocal ¶
VaultLocal initialises the per-vault config (.hebb/config.toml, created with defaults if absent, never clobbered). It is idempotent. The project-scoped .mcp.json is written separately and only on request (Options.MCPJSON): the hebb plugin normally provides the MCP server.
type Step ¶
type Step struct {
Name string
Status string // created | exists | wrote | unchanged | symlinked | loaded ...
}
Step records the outcome of one install action for reporting.
type TeardownOptions ¶
type TeardownOptions struct {
VaultPath string
Home string // base dir holding .claude; "" disables the memory step
LaunchdDir string // "" -> <home>/Library/LaunchAgents
CodexConfig string // "" -> <home>/.codex/config.toml
DesktopConfig string // "" -> the macOS Claude Desktop config under Home
MCPName string // server/block name (default "hebb")
RegistryPath string // "" -> <home>/.config/hebb/vaults.toml via core.RegistryPath
Force bool // false = dry run
KeepIndex bool // default false -> clear .hebb/index.db (cheap to rebuild)
}
TeardownOptions configures `hebb reset`: un-wire a vault from this machine. Directory fields are explicit so it is hermetically testable. Force=false is a dry run (report only, mutate nothing).
type TeardownReport ¶
type TeardownReport struct {
Forced bool
Steps []TeardownStep
}
TeardownReport is the outcome of Teardown.
func Teardown ¶
func Teardown(opts TeardownOptions) (TeardownReport, error)
Teardown removes only the machine-side wiring `hebb install` created. It NEVER touches vault content: markdown notes, .hebb/memory, and .hebb/config.toml are always left intact. Steps (each tolerant of being absent):
- memory symlink in <home>/.claude/projects/<slug>/memory (the link only)
- launchd plists local.hebb.<slug>.* (+ best-effort bootout)
- the [mcp_servers.<name>] block in ~/.codex/config.toml
- the opt-in per-vault .mcp.json (only if hebb-generated) and the hebb entry in <vault>/.claude/settings.json
- .hebb/index.db (derived; unless KeepIndex)
type TeardownStep ¶
type TeardownStep struct {
Target string // what
Status string // "removed" | "would remove" | "absent" | "skipped: <why>"
}
TeardownStep is one action in the teardown plan/report.
type Updater ¶
type Updater struct {
Repo string
APIBase string // default https://api.github.com
DownloadBase string // default https://github.com
HTTP *http.Client
UseGH bool
}
Updater fetches release metadata and assets. URLs are fields so tests can point them at a local server; defaults target GitHub. When UseGH is set and the gh CLI is available and authed, it is used (works for a private repo), mirroring install.sh.
func NewUpdater ¶
func NewUpdater() Updater
NewUpdater returns an Updater with GitHub defaults and gh enabled.
func (Updater) DownloadBinary ¶
DownloadBinary fetches the asset and checksums for tag/platform, verifies the checksum, and returns the extracted hebb binary.