tools

package
v1.1.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 7, 2026 License: GPL-3.0 Imports: 20 Imported by: 0

Documentation

Overview

Package tools implements sync82's MCP tools — one exported type per tool (CreateProjectTool, ReadMemoryTool, WriteMemoryTool, and so on), each implementing the common Tool interface: Name, Description, InputSchema, and a Validate/Execute pair. The server turns an error from either step into a tool result with IsError set, so the calling agent can read the message and retry with corrected input.

Resolver implements the three-tier project-resolution cascade (explicit "project" argument, .sync82.json at workspace_root — or, opt-in, discovered by walking up from it — and the global config's last-used project) that every project-scoped tool relies on. Logic shared by more than one tool lives in one place: kind-name validation and the six standard kinds (validateKind, standardKinds), the "## YYYY-MM-DD" header append-only kinds use (dateHeaderPattern), the write/append logic shared by write_memory, append_memory, and update_project_memory (writeMemoryCore, appendMemoryCore), and export/import (ExportProject, ImportProject, also called directly by the "sync82" CLI's export/import subcommands).

Index

Constants

View Source
const NeedsInputMessage = `` /* 412-byte string literal not displayed */

NeedsInputMessage is returned as a normal tool result (not an error result) when no resolution tier finds a project. It is instructional text for the calling agent.

View Source
const PathDescription = `` /* 203-byte string literal not displayed */

PathDescription is the description text used on every tool schema's optional "path" field.

View Source
const ResourceMIMEType = "text/markdown"

ResourceMIMEType is the MIME type of every sync82 resource.

View Source
const SearchParentDirsDescription = `` /* 208-byte string literal not displayed */

SearchParentDirsDescription is the description text used on every tool schema's optional "search_parent_dirs" field. Looking for .sync82.json only at workspace_root itself is the default: a .sync82.json found in a parent directory the caller doesn't control could silently redirect where memory is stored, since its "path" field is trusted without confirmation.

Variables

View Source
var ErrResourceNotFound = errors.New("resource not found")

ErrResourceNotFound is returned by Resources.Read when a URI is not a sync82 resource URI, names an invalid or missing project or file, or the default vault does not exist.

View Source
var Prompts = []PromptDefinition{
	{
		Name:        "start_session",
		Title:       "Start a session with the project memory",
		Description: "Load the project's sync82 memory and summarize where the work stands.",
		Arguments:   promptTargetArguments,
		Render:      renderStartSession,
	},
	{
		Name:        "end_session",
		Title:       "Save this session to the project memory",
		Description: "Record what this session did, decided and left pending in the project's sync82 memory.",
		Arguments:   promptTargetArguments,
		Render:      renderEndSession,
	},
}

Prompts lists the MCP prompts sync82 exposes.

View Source
var ResourceTemplates = []ResourceTemplate{
	{
		URITemplate: resourceScheme + "{project}/context",
		Name:        "project-context",
		Title:       "Project context",
		Description: "A project's memory in one block, as load_project_context returns it by default: current-state files in full and the 10 most recent entries of each log.",
	},
	{
		URITemplate: resourceScheme + "{project}/files/{file}",
		Name:        "project-file",
		Title:       "Project memory file",
		Description: "One memory file of a project (memory, architecture, stack, decisions, progress, next_steps or a custom one), as read_memory returns it.",
	},
	{
		URITemplate: resourceScheme + "{project}/subprojects/{subproject}/context",
		Name:        "subproject-context",
		Title:       "Subproject context",
		Description: "A subproject's memory in one block, as load_project_context returns it by default.",
	},
	{
		URITemplate: resourceScheme + "{project}/subprojects/{subproject}/files/{file}",
		Name:        "subproject-file",
		Title:       "Subproject memory file",
		Description: "One memory file of a subproject, as read_memory returns it.",
	},
}

ResourceTemplates lists the resource templates the server exposes, all read from the default vault.

Functions

func ContextNote

func ContextNote(ctx ResolvedContext) string

ContextNote returns the " [project: x, from ..., vault: ...]" suffix tool responses append when the project was auto-discovered rather than passed explicitly. It always includes the resolved vault path, so a caller relying on auto-discovery can see which vault was used. It returns "" for SourceProvided, where the caller named the project.

func ExportProject

func ExportProject(ctx context.Context, s *store.Store, project, subproject, outputDir string, overwrite bool) (int, error)

ExportProject writes one <kind>.md file per kind of the given project and subproject in s into outputDir — the standard kinds and any custom kind, each rendered as read_memory returns it (entries concatenated in date order, with their "## YYYY-MM-DD" headers). A kind with archived entries also gets a <kind>.archived.md file holding those entries in the same format, so an export keeps the whole history and importing it restores the archive.

Nothing is written when a destination exists but isn't a regular file (a symlink could redirect the write elsewhere), nor, unless overwrite is true, when a destination file already exists; the error then wraps errExportWouldOverwrite and names every colliding file. A missing outputDir is created, and new files and directories are private to the user. It returns the number of files written (0 when the project has no content), or an error if listing, reading or writing fails; a write failure part-way through reports the files written before it.

It is the entry point shared by the export_memory tool and the "sync82 export" command.

func FormatImportReport

func FormatImportReport(r ImportReport, target, inputDir string, dryRun bool) string

FormatImportReport renders r as the text the import_memory tool and the "sync82 import" command print. target is the project label the files go into, inputDir the directory they came from, and dryRun selects the wording for an import that wrote nothing.

func FormatLabel

func FormatLabel(project, subproject string) string

FormatLabel formats a project/subproject pair the way tool responses do: "project" alone when subproject is empty, otherwise "project/subproject".

func NormalizeName

func NormalizeName(name string) string

NormalizeName returns a project or subproject name as it is stored: trimmed and lower-cased, so names differing only in case are the same project.

func ValidateTarget

func ValidateTarget(project, subproject string) error

ValidateTarget checks project and, when non-empty, subproject against the project-name rules. Every path that creates or resolves a project goes through it, so a name that could escape a directory when used as a folder name ("../x", "a/b") never reaches the vault.

Types

type AppendMemoryTool

type AppendMemoryTool struct {
	Resolver *Resolver
	Stores   *store.Manager
}

AppendMemoryTool implements append_memory: add a new entry to an append-only kind. A "## YYYY-MM-DD" date header is required only for the two standard append-only kinds (progress, decisions); a custom kind never requires one. Validation and execution delegate to validateAppendInput and appendMemoryCore, shared with update_project_memory.

func (*AppendMemoryTool) Description

func (t *AppendMemoryTool) Description() string

Description returns the text shown to the calling agent that explains what the tool does and how to use it.

func (*AppendMemoryTool) Execute

func (t *AppendMemoryTool) Execute(ctx context.Context, rawArgs any) (ToolResult, error)

Execute resolves the target project and appends the content as a new entry of the kind through appendMemoryCore. Appending to an overwrite-style kind returns an error result (IsError) that points to write_memory; an unresolved project returns the instructional result; other failures are returned as errors.

func (*AppendMemoryTool) InputSchema

func (t *AppendMemoryTool) InputSchema() map[string]any

InputSchema returns the JSON Schema of the tool's arguments: an object with the required properties filename and content plus the project- resolution properties.

func (*AppendMemoryTool) Name

func (t *AppendMemoryTool) Name() string

Name returns the MCP tool name, "append_memory".

func (*AppendMemoryTool) Validate

func (t *AppendMemoryTool) Validate(raw json.RawMessage) (any, error)

Validate decodes raw into appendMemoryArgs and checks filename and content with validateAppendInput. It returns the arguments with Filename normalized to its lower-case kind name, or an error describing the first violated rule.

type ArchiveMemoryTool

type ArchiveMemoryTool struct {
	Resolver *Resolver
	Stores   *store.Manager
}

ArchiveMemoryTool implements archive_memory: marks old dated entries in progress or decisions as archived through store.ArchiveEntries, optionally adding a summary of them as a new entry in the same transaction, or only lists them on a dry run. Entries with no date header are never archived, regardless of age.

func (*ArchiveMemoryTool) Description

func (t *ArchiveMemoryTool) Description() string

Description returns the text shown to the calling agent that explains what the tool does and how to use it.

func (*ArchiveMemoryTool) Execute

func (t *ArchiveMemoryTool) Execute(ctx context.Context, rawArgs any) (ToolResult, error)

Execute resolves the target project and archives the dated entries older than KeepDays days (UTC), adding Summary as a new entry when one is given, then reports how many were archived and kept. With DryRun it only lists the entries it would archive. It refuses, with an error result, to act on a project that was only taken from the last session; store failures are returned as errors.

func (*ArchiveMemoryTool) InputSchema

func (t *ArchiveMemoryTool) InputSchema() map[string]any

InputSchema returns the JSON Schema of the tool's arguments: an object with the required property filename (progress or decisions), an optional keep_days and the project-resolution properties.

func (*ArchiveMemoryTool) Name

func (t *ArchiveMemoryTool) Name() string

Name returns the MCP tool name, "archive_memory".

func (*ArchiveMemoryTool) Validate

func (t *ArchiveMemoryTool) Validate(raw json.RawMessage) (any, error)

Validate decodes raw into archiveMemoryArgs. It returns the arguments, with Filename trimmed and lower-cased, KeepDays defaulting to 90 and entry id marker lines removed from Summary, or an error when filename is not an append-only standard kind, keep_days is outside 1 to maxKeepDays, or summary is given but blank, larger than maxContentSize or dated by a header older than the archive cutoff, which the next archive would archive again.

type CheckProjectHealthTool

type CheckProjectHealthTool struct {
	Resolver *Resolver
	Stores   *store.Manager
}

func (*CheckProjectHealthTool) Description

func (t *CheckProjectHealthTool) Description() string

Description returns the text shown to the calling agent that explains what the tool does and how to use it.

func (*CheckProjectHealthTool) Execute

func (t *CheckProjectHealthTool) Execute(ctx context.Context, rawArgs any) (ToolResult, error)

Execute resolves the target project, checks that each standard kind exists and collects the healthWarnings. The result is a text or JSON report; its IsError flag is set when any standard kind is missing, never for warnings alone. Store failures are returned as errors.

func (*CheckProjectHealthTool) InputSchema

func (t *CheckProjectHealthTool) InputSchema() map[string]any

InputSchema returns the JSON Schema of the tool's arguments: an object with the optional property format plus the project-resolution properties.

func (*CheckProjectHealthTool) Name

func (t *CheckProjectHealthTool) Name() string

Name returns the MCP tool name, "check_project_health".

func (*CheckProjectHealthTool) Validate

func (t *CheckProjectHealthTool) Validate(raw json.RawMessage) (any, error)

Validate decodes raw into checkProjectHealthArgs, normalizes format to "text" or "json" and defaults StaleDays to defaultStaleDays. It returns the arguments, or an error when format is invalid or stale_days is negative.

type ContextArgs

type ContextArgs struct {
	Project          string
	Subproject       string
	Path             string
	WorkspaceRoot    string
	SearchParentDirs bool
}

ContextArgs holds the subset of a tool call's arguments relevant to context resolution. Every field is the empty string when the calling agent omitted it — exactly how a parsed JSON-RPC request would leave an absent optional field.

type ContextSource

type ContextSource string

ContextSource records which resolution tier produced a ResolvedContext, so ContextNote can explain it back to the calling agent.

const (
	SourceProvided     ContextSource = "provided"
	SourceLocalConfig  ContextSource = "local_config"
	SourceGlobalConfig ContextSource = "global_config"
)

Values of ContextSource: an explicit project argument, a .sync82.json file, and the global config's last-used project.

type CreateProjectTool

type CreateProjectTool struct {
	Resolver *Resolver
	Stores   *store.Manager
}

CreateProjectTool implements create_project: get-or-create a project or subproject, creating the parent if it doesn't exist yet. No documents or entries are seeded.

func (*CreateProjectTool) Description

func (t *CreateProjectTool) Description() string

Description returns the text shown to the calling agent that explains what the tool does and how to use it.

func (*CreateProjectTool) Execute

func (t *CreateProjectTool) Execute(ctx context.Context, rawArgs any) (ToolResult, error)

Execute opens the vault at the requested path, creating it if needed, and ensures the project or subproject exists, creating its parent when necessary. The result says whether it was created or already existed; store failures are returned as errors.

func (*CreateProjectTool) InputSchema

func (t *CreateProjectTool) InputSchema() map[string]any

InputSchema returns the JSON Schema of the tool's arguments: an object with the required property project, an optional subproject and an optional vault path.

func (*CreateProjectTool) Name

func (t *CreateProjectTool) Name() string

Name returns the MCP tool name, "create_project".

func (*CreateProjectTool) Validate

func (t *CreateProjectTool) Validate(raw json.RawMessage) (any, error)

Validate decodes raw into createProjectArgs, normalizes the names and checks them against the project-name rules. It returns the arguments, or an error listing every invalid field.

type DeleteMemoryTool

type DeleteMemoryTool struct {
	Resolver *Resolver
	Stores   *store.Manager
}

DeleteMemoryTool implements delete_memory: delete a custom document/entries kind. The six standard kinds are protected and cannot be deleted.

func (*DeleteMemoryTool) Description

func (t *DeleteMemoryTool) Description() string

Description returns the text shown to the calling agent that explains what the tool does and how to use it.

func (*DeleteMemoryTool) Execute

func (t *DeleteMemoryTool) Execute(ctx context.Context, rawArgs any) (ToolResult, error)

Execute resolves the target project and deletes the custom kind. It refuses, with an error result, to act on a project that was only taken from the last session; a missing project or kind and other store failures are returned as errors.

func (*DeleteMemoryTool) InputSchema

func (t *DeleteMemoryTool) InputSchema() map[string]any

InputSchema returns the JSON Schema of the tool's arguments: an object with the required properties filename and confirm plus the project- resolution properties.

func (*DeleteMemoryTool) Name

func (t *DeleteMemoryTool) Name() string

Name returns the MCP tool name, "delete_memory".

func (*DeleteMemoryTool) Validate

func (t *DeleteMemoryTool) Validate(raw json.RawMessage) (any, error)

Validate decodes raw into deleteMemoryArgs. It returns the arguments with Filename lower-cased, or an error when filename is not a valid kind name, names one of the standard kinds, or confirm is not true.

type DeleteProjectTool

type DeleteProjectTool struct {
	Resolver *Resolver
	Stores   *store.Manager
}

DeleteProjectTool implements delete_project: delete a project or a subproject. Deleting a project that has subprojects takes two calls: the first lists them and asks for a subproject_action, the second carries it out.

func (*DeleteProjectTool) Description

func (t *DeleteProjectTool) Description() string

Description returns the text shown to the calling agent that explains what the tool does and how to use it.

func (*DeleteProjectTool) Execute

func (t *DeleteProjectTool) Execute(ctx context.Context, rawArgs any) (ToolResult, error)

Execute deletes a subproject, or a top-level project. When the project has subprojects and no subproject_action was given, it returns a non-error result that asks the caller to choose "cancel", "promote" or "delete_all". Promotion and deletion happen in one transaction, so a failure changes nothing. After a deletion, a last used project (or subproject) that no longer exists is forgotten, and one that was promoted is followed to its new name. A missing vault yields an error result; other failures are returned as errors.

func (*DeleteProjectTool) InputSchema

func (t *DeleteProjectTool) InputSchema() map[string]any

InputSchema returns the JSON Schema of the tool's arguments: an object with the required properties project and confirm, an optional subproject, an optional subproject_action and an optional vault path.

func (*DeleteProjectTool) Name

func (t *DeleteProjectTool) Name() string

Name returns the MCP tool name, "delete_project".

func (*DeleteProjectTool) Validate

func (t *DeleteProjectTool) Validate(raw json.RawMessage) (any, error)

Validate decodes raw into deleteProjectArgs and normalizes the names. It returns the arguments, or an error listing every problem: an invalid name, confirm not true, or an unknown subproject_action.

type EditEntryTool added in v1.1.0

type EditEntryTool struct {
	Resolver *Resolver
	Stores   *store.Manager
}

EditEntryTool implements edit_entry: replace, delete or supersede one entry of an append-only kind, identified by the id read_memory shows with with_ids. Like the other destructive tools, it refuses a project that was only taken from the last session.

func (*EditEntryTool) Description added in v1.1.0

func (t *EditEntryTool) Description() string

Description returns the text shown to the calling agent that explains what the tool does and how to use it.

func (*EditEntryTool) Execute added in v1.1.0

func (t *EditEntryTool) Execute(ctx context.Context, rawArgs any) (ToolResult, error)

Execute resolves the target project and applies the action to the entry. It returns an error result (IsError) when the project was only taken from the last session, the kind is stored as an overwrite-style document, or the entry does not belong to the project and kind; an unresolved project returns the instructional result; a missing project yields the error built by wrapNotFound; other failures are returned as errors.

func (*EditEntryTool) InputSchema added in v1.1.0

func (t *EditEntryTool) InputSchema() map[string]any

InputSchema returns the JSON Schema of the tool's arguments: an object with the required properties filename, entry_id and action, the optional content and confirm, plus the project-resolution properties.

func (*EditEntryTool) Name added in v1.1.0

func (t *EditEntryTool) Name() string

Name returns the MCP tool name, "edit_entry".

func (*EditEntryTool) Validate added in v1.1.0

func (t *EditEntryTool) Validate(raw json.RawMessage) (any, error)

Validate decodes raw into editEntryArgs. For replace and supersede it removes entry id marker lines from content and checks filename and content with validateAppendInput; for delete it checks filename, that no content is given and that confirm is true. It returns the arguments with Filename lower-cased, or an error when an argument is invalid, the kind is an overwrite-style standard kind, or entry_id is not positive.

type ExportMemoryTool

type ExportMemoryTool struct {
	Resolver *Resolver
	Stores   *store.Manager
}

ExportMemoryTool implements export_memory: writes every memory file of a project out to plain .md files on disk, for browsing outside an MCP client or a git-diffable history. The export itself is done by ExportProject, which the "sync82 export" command also uses.

func (*ExportMemoryTool) Description

func (t *ExportMemoryTool) Description() string

Description returns the text shown to the calling agent that explains what the tool does and how to use it.

func (*ExportMemoryTool) Execute

func (t *ExportMemoryTool) Execute(ctx context.Context, rawArgs any) (ToolResult, error)

Execute resolves the target project and exports its kinds to output_dir through exportProjectCore. It reports the number of files written; existing destination files without Overwrite yield an error result, and other failures are returned as errors.

func (*ExportMemoryTool) InputSchema

func (t *ExportMemoryTool) InputSchema() map[string]any

InputSchema returns the JSON Schema of the tool's arguments: an object with the required property output_dir, an optional overwrite and the project-resolution properties.

func (*ExportMemoryTool) Name

func (t *ExportMemoryTool) Name() string

Name returns the MCP tool name, "export_memory".

func (*ExportMemoryTool) Validate

func (t *ExportMemoryTool) Validate(raw json.RawMessage) (any, error)

Validate decodes raw into exportMemoryArgs and checks that output_dir is an absolute directory (after ~ or HOME expansion). It returns the arguments with OutputDir expanded and cleaned, or an error.

type GetVaultConfigTool

type GetVaultConfigTool struct {
	Resolver *Resolver
	Stores   *store.Manager
}

GetVaultConfigTool implements get_vault_config: report the current effective configuration — active vault path, global config, and (if workspace_root is given) the local config plus that project's subprojects.

func (*GetVaultConfigTool) Description

func (t *GetVaultConfigTool) Description() string

Description returns the text shown to the calling agent that explains what the tool does and how to use it.

func (*GetVaultConfigTool) Execute

func (t *GetVaultConfigTool) Execute(ctx context.Context, rawArgs any) (ToolResult, error)

Execute returns a JSON report with the active vault path, the global config's vault and last-used project and, when workspace_root is given, the local .sync82.json together with the subprojects of its project. Failure to read a config or the vault is returned as an error.

func (*GetVaultConfigTool) InputSchema

func (t *GetVaultConfigTool) InputSchema() map[string]any

InputSchema returns the JSON Schema of the tool's arguments: an object with the optional properties workspace_root, search_parent_dirs and path.

func (*GetVaultConfigTool) Name

func (t *GetVaultConfigTool) Name() string

Name returns the MCP tool name, "get_vault_config".

func (*GetVaultConfigTool) Validate

func (t *GetVaultConfigTool) Validate(raw json.RawMessage) (any, error)

Validate decodes raw into getVaultConfigArgs. It has no further rules and returns an error only when decoding fails.

type ImportMemoryTool

type ImportMemoryTool struct {
	Resolver *Resolver
	Stores   *store.Manager
}

ImportMemoryTool implements import_memory: the inverse of export_memory — reads every "<kind>.md" file from a local directory and writes each into the resolved project, creating the project first if it doesn't exist yet. Like write_memory, it replaces an existing kind's content rather than merging it. The import itself is done by ImportProject, which the "sync82 import" command also uses.

func (*ImportMemoryTool) Description

func (t *ImportMemoryTool) Description() string

Description returns the text shown to the calling agent that explains what the tool does and how to use it.

func (*ImportMemoryTool) Execute

func (t *ImportMemoryTool) Execute(ctx context.Context, rawArgs any) (ToolResult, error)

Execute resolves the target project, creating the vault if needed (but not on a dry run), and imports the Markdown files in input_dir through importProjectCore, or only reports what would change when DryRun is set. A project taken only from the last session yields an error result instead of being imported into; other failures are returned as errors.

func (*ImportMemoryTool) InputSchema

func (t *ImportMemoryTool) InputSchema() map[string]any

InputSchema returns the JSON Schema of the tool's arguments: an object with the required property input_dir, an optional dry_run and the project- resolution properties.

func (*ImportMemoryTool) Name

func (t *ImportMemoryTool) Name() string

Name returns the MCP tool name, "import_memory".

func (*ImportMemoryTool) Validate

func (t *ImportMemoryTool) Validate(raw json.RawMessage) (any, error)

Validate decodes raw into importMemoryArgs and checks that input_dir is an absolute directory (after ~ or HOME expansion). It returns the arguments with InputDir expanded and cleaned, or an error.

type ImportReport

type ImportReport struct {
	Created     []string
	Overwritten []string
	Skipped     []string
}

ImportReport lists the file names of an import by outcome: Created for kinds that don't exist yet, Overwritten for kinds whose content the file replaces, Skipped for files that aren't imported (not a valid kind name, empty, too large, or not a regular file).

func ImportProject

func ImportProject(ctx context.Context, s *store.Store, project, subproject, inputDir string, dryRun bool) (ImportReport, error)

ImportProject is the inverse of ExportProject: it reads every "<kind>.md" file in inputDir and writes it into the given project and subproject of s the way write_memory would (an append-only kind's content is split into dated sections with splitByDateHeader; an overwrite-style kind is written as-is). A "<kind>.archived.md" file replaces that kind's archived entries; without one, the archived entries already in the vault are kept. The project is created when missing.

The import is all or nothing: every file is read and checked first, and the writes are then applied in one transaction, so a failure leaves the vault unchanged. With dryRun, nothing is written and the report says what the import would do. Files that cannot be imported are listed in the report as skipped. It returns an error when the project or subproject name is invalid, inputDir cannot be read, it holds more than maxImportFiles ".md" files or more than maxImportTotalBytes of them, two files differ only in case, or a store operation fails. s may be nil only with dryRun, for a vault that does not exist yet: every file is then reported as new.

It is the entry point shared by the import_memory tool and the "sync82 import" command.

func (ImportReport) Imported

func (r ImportReport) Imported() int

Imported returns the number of files the import writes: those created plus those overwritten.

type InitProjectMemoryTool

type InitProjectMemoryTool struct {
	Resolver *Resolver
	Stores   *store.Manager
}

InitProjectMemoryTool implements init_project_memory: create a project or subproject and fill its standard documents from the given answers and, optionally, an analysis of the workspace. Documents that already have content are left untouched.

func (*InitProjectMemoryTool) Description

func (t *InitProjectMemoryTool) Description() string

Description returns the multi-step instruction script for the calling agent.

func (*InitProjectMemoryTool) Execute

func (t *InitProjectMemoryTool) Execute(ctx context.Context, rawArgs any) (ToolResult, error)

Execute determines the target (see resolveTarget), creates the project when needed and writes the four standard documents that are missing or still blank, filled from the answers and the analyzer's findings. With workspace_root it also writes .sync82.json unless one already maps the workspace to another project. It returns the instructional text when no project can be determined, and an error result when the workspace's .sync82.json cannot be read or the determined project or subproject name is invalid; store failures are returned as errors.

func (*InitProjectMemoryTool) InputSchema

func (t *InitProjectMemoryTool) InputSchema() map[string]any

InputSchema returns the JSON Schema of the tool's arguments: an object whose properties are the project-resolution ones, auto_detect and the answers used to fill the standard documents.

func (*InitProjectMemoryTool) Name

func (t *InitProjectMemoryTool) Name() string

Name returns the MCP tool name, "init_project_memory".

func (*InitProjectMemoryTool) Validate

func (t *InitProjectMemoryTool) Validate(raw json.RawMessage) (any, error)

Validate decodes raw into initProjectMemoryArgs. It returns the arguments, or an error when auto_detect is set without workspace_root, a given project or subproject name is invalid, or the answers exceed maxContentSize in total.

type ListFilesTool

type ListFilesTool struct {
	Resolver *Resolver
	Stores   *store.Manager
}

ListFilesTool implements list_files: list every document kind and entry kind of the resolved project. "File" here means a kind stored in the vault database, not a file on disk.

func (*ListFilesTool) Description

func (t *ListFilesTool) Description() string

Description returns the text shown to the calling agent that explains what the tool does and how to use it.

func (*ListFilesTool) Execute

func (t *ListFilesTool) Execute(ctx context.Context, rawArgs any) (ToolResult, error)

Execute resolves the target project and lists its kinds, with size, estimated tokens and last-modified date per kind when Metadata is set. The output is text or JSON; the JSON form is also returned as structured content. Store failures are returned as errors.

func (*ListFilesTool) InputSchema

func (t *ListFilesTool) InputSchema() map[string]any

InputSchema returns the JSON Schema of the tool's arguments: an object with the optional properties metadata and format plus the project- resolution properties.

func (*ListFilesTool) Name

func (t *ListFilesTool) Name() string

Name returns the MCP tool name, "list_files".

func (*ListFilesTool) Validate

func (t *ListFilesTool) Validate(raw json.RawMessage) (any, error)

Validate decodes raw into listFilesArgs and normalizes format to "text" or "json". It returns the arguments, or an error when format is invalid.

type ListProjectsTool

type ListProjectsTool struct {
	Resolver *Resolver
	Stores   *store.Manager
}

ListProjectsTool implements list_projects: list every top-level project, each followed by its subprojects. It doesn't target a specific project, so it only resolves the vault path.

func (*ListProjectsTool) Description

func (t *ListProjectsTool) Description() string

Description returns the text shown to the calling agent that explains what the tool does and how to use it.

func (*ListProjectsTool) Execute

func (t *ListProjectsTool) Execute(ctx context.Context, rawArgs any) (ToolResult, error)

Execute lists every top-level project with its subprojects in the vault. A vault that does not exist is reported as an empty list rather than created. The output is text or JSON; store failures are returned as errors.

func (*ListProjectsTool) InputSchema

func (t *ListProjectsTool) InputSchema() map[string]any

InputSchema returns the JSON Schema of the tool's arguments: an object with the optional properties format and path.

func (*ListProjectsTool) Name

func (t *ListProjectsTool) Name() string

Name returns the MCP tool name, "list_projects".

func (*ListProjectsTool) Validate

func (t *ListProjectsTool) Validate(raw json.RawMessage) (any, error)

Validate decodes raw into listProjectsArgs and normalizes format to "text" or "json". It returns the arguments, or an error when format is invalid.

type LoadProjectContextTool

type LoadProjectContextTool struct {
	Resolver *Resolver
	Stores   *store.Manager
}

LoadProjectContextTool implements load_project_context: concatenate every non-blank document/entries kind into one context block, current state first, skipping blank kinds. "Blank" means the kind's content trims to the empty string, either because it holds only whitespace or because filteredContent left nothing after its since/max_entries filtering.

"since" and "max_entries" optionally narrow the dated history of an entries-backed kind (progress, decisions, or a custom append kind), so a long-running project doesn't load every past entry each time. An overwrite-style document (memory, architecture, stack, next_steps, or a custom write-mode kind) represents current state, not history, so the filter never applies to one — see filteredContent. "mode" picks the defaults: "summary" (the default) keeps the most recent summaryMaxEntries dated entries per kind within summaryContextBytes, "full" keeps every entry within fullContextBytes. When dated entries are left out, a footer says how many per kind. The response is cut at max_bytes.

func (*LoadProjectContextTool) Description

func (t *LoadProjectContextTool) Description() string

Description returns the text shown to the calling agent that explains what the tool does and how to use it.

func (*LoadProjectContextTool) Execute

func (t *LoadProjectContextTool) Execute(ctx context.Context, rawArgs any) (ToolResult, error)

Execute resolves the target project and concatenates the non-blank content of its kinds (all of them, or only the requested files) into one block, current-state kinds first, applying since and max_entries to dated history. When dated entries are left out, a footer lists, per kind, how many were shown out of how many. The block is cut at MaxBytes, footer included. Store failures are returned as errors.

func (*LoadProjectContextTool) InputSchema

func (t *LoadProjectContextTool) InputSchema() map[string]any

InputSchema returns the JSON Schema of the tool's arguments: an object with the optional properties files, since, max_entries and max_bytes plus the project-resolution properties.

func (*LoadProjectContextTool) Name

func (t *LoadProjectContextTool) Name() string

Name returns the MCP tool name, "load_project_context".

func (*LoadProjectContextTool) Validate

func (t *LoadProjectContextTool) Validate(raw json.RawMessage) (any, error)

Validate decodes raw into loadProjectContextArgs. It lower-cases and checks each file name and the since date, and fills in the mode defaults: Mode defaults to summary; in summary mode MaxEntries defaults to summaryMaxEntries when neither since nor max_entries is given; MaxBytes defaults to summaryContextBytes or fullContextBytes by mode. It returns the arguments, or an error when a file name, since or mode is invalid, max_entries is negative or max_bytes is out of range.

type PromptArgument added in v1.1.0

type PromptArgument struct {
	Name        string
	Description string
	Required    bool
}

PromptArgument is one argument of a sync82 prompt.

type PromptDefinition added in v1.1.0

type PromptDefinition struct {
	Name        string
	Title       string
	Description string
	Arguments   []PromptArgument
	Render      func(args map[string]string) (string, error)
}

PromptDefinition is one MCP prompt sync82 exposes: its name, texts, arguments, and Render, which turns the arguments given by the client into the instruction sent to the agent as a user message. Prompts never read or write the vault: they only tell the agent which tools to call.

type ReadMemoryTool

type ReadMemoryTool struct {
	Resolver *Resolver
	Stores   *store.Manager
}

ReadMemoryTool implements read_memory: for an overwrite-style document, return its content; for an append-only entries collection, concatenate all non-archived entries in date order, each preceded by an entry id marker line when with_ids is set.

func (*ReadMemoryTool) Description

func (t *ReadMemoryTool) Description() string

Description returns the text shown to the calling agent that explains what the tool does and how to use it.

func (*ReadMemoryTool) Execute

func (t *ReadMemoryTool) Execute(ctx context.Context, rawArgs any) (ToolResult, error)

Execute resolves the target project and returns the kind's content with surrounding whitespace trimmed, or "(file is empty)" when nothing remains. With WithIDs, an entries-backed kind is returned entry by entry, each preceded by its entryMarker line. It returns an error when the project or the kind does not exist.

func (*ReadMemoryTool) InputSchema

func (t *ReadMemoryTool) InputSchema() map[string]any

InputSchema returns the JSON Schema of the tool's arguments: an object with the required property filename plus the project-resolution properties.

func (*ReadMemoryTool) Name

func (t *ReadMemoryTool) Name() string

Name returns the MCP tool name, "read_memory".

func (*ReadMemoryTool) Validate

func (t *ReadMemoryTool) Validate(raw json.RawMessage) (any, error)

Validate decodes raw into readMemoryArgs and checks that filename is a valid kind name. It returns the arguments with Filename lower-cased, or an error.

type RenameProjectTool

type RenameProjectTool struct {
	Resolver *Resolver
	Stores   *store.Manager
}

RenameProjectTool implements rename_project: rename a top-level project or a specific subproject in place. Only the vault and the global config's last-used project change — any .sync82.json elsewhere on disk that points at the old name keeps doing so until re-initialized or edited by hand.

func (*RenameProjectTool) Description

func (t *RenameProjectTool) Description() string

Description returns the text shown to the calling agent that explains what the tool does and how to use it.

func (*RenameProjectTool) Execute

func (t *RenameProjectTool) Execute(ctx context.Context, rawArgs any) (ToolResult, error)

Execute renames the project, or the subproject when one is given, and keeps the global config's last-used project in step. A name collision or a missing vault yields an error result; other failures are returned as errors.

func (*RenameProjectTool) InputSchema

func (t *RenameProjectTool) InputSchema() map[string]any

InputSchema returns the JSON Schema of the tool's arguments: an object with the required properties project and new_name, an optional subproject and an optional vault path.

func (*RenameProjectTool) Name

func (t *RenameProjectTool) Name() string

Name returns the MCP tool name, "rename_project".

func (*RenameProjectTool) Validate

func (t *RenameProjectTool) Validate(raw json.RawMessage) (any, error)

Validate decodes raw into renameProjectArgs and normalizes the names. It returns the arguments, or an error listing every invalid or missing field.

type ResolvedContext

type ResolvedContext struct {
	OK          bool
	Project     string
	Subproject  string
	DBPath      string
	Source      ContextSource
	Problem     string
	InvalidName bool
}

ResolvedContext is the outcome of resolving a tool call's target project. OK is false when no resolution tier produced an answer — callers must return NeedsInput() as a normal (non-error) tool result in that case, not fail the call. Problem, when set, explains why a given workspace_root could not be used, or — with InvalidName — why the resolved project or subproject name was rejected.

func (ResolvedContext) Label

func (c ResolvedContext) Label() string

Label returns the context's project and subproject formatted by FormatLabel.

func (ResolvedContext) NeedsInput

func (c ResolvedContext) NeedsInput() string

NeedsInput returns the tool result text for an unresolved context: NeedsInputMessage, preceded by Problem when one is set.

type Resolver

type Resolver struct {
	DefaultDBPath string
	Logger        *slog.Logger
}

Resolver implements the three-tier context resolution every tool relies on: an explicit project argument wins outright; otherwise, when workspace_root is given, the .sync82.json there (or, opt-in via SearchParentDirs, discovered by walking up from it) and nothing else; otherwise the global config's last-used project. DefaultDBPath is the vault used when nothing else names one, and Logger receives diagnostics.

func NewResolver

func NewResolver(defaultDBPath string, logger *slog.Logger) *Resolver

NewResolver returns a Resolver that falls back to defaultDBPath as the vault and logs to logger. logger must not be nil; pass slog.New(slog.DiscardHandler) to silence logging.

func (*Resolver) DBPathOrDefault

func (r *Resolver) DBPathOrDefault(rawPath string) string

DBPathOrDefault resolves a tool call's optional "path" argument, rawPath, to a concrete vault path: the explicit path when given, otherwise the global config's vault path ("sync82 config set-vault"), otherwise DefaultDBPath. The tools that don't need full context resolution (list_projects, create_project, delete_project, rename_project, get_vault_config) and the export/import CLI commands use this directly.

func (*Resolver) RememberIfExists

func (r *Resolver) RememberIfExists(ctx context.Context, s *store.Store, rctx ResolvedContext)

RememberIfExists records rctx as the last-used project, together with its vault path, when that project exists in s, so a call naming a project that doesn't exist (a typo) never becomes the default for later calls. A context resolved from tier 3 is already the remembered one and is left alone. Failures are logged and never returned.

func (*Resolver) Resolve

func (r *Resolver) Resolve(args ContextArgs) ResolvedContext

Resolve runs the three-tier resolution for a single tool call and returns the resolved context, with the project and subproject names validated and normalized. It never returns an error: a failure to resolve is represented by OK: false, with Problem set when the cause is an unusable workspace_root or an invalid name (InvalidName).

An explicit subproject argument is kept in every tier. When workspace_root is given, tier 3 is never consulted: a missing or invalid .sync82.json there yields OK: false instead of silently falling back to whatever project another session used last.

func (*Resolver) ResolveStore

func (r *Resolver) ResolveStore(ctx context.Context, stores *store.Manager, args ContextArgs) (s *store.Store, rctx ResolvedContext, ready *ToolResult, err error)

ResolveStore resolves the call's context, opens the resulting vault and remembers the project as last used when it exists there — the "resolve context, then open the store" sequence every project-scoped memory tool runs first. args are the call's context arguments.

Exactly one of three outcomes occurs:

  • ready != nil: resolution failed (no project could be determined, or its name is invalid). The caller must return *ready as-is (NeedsInput() or an error result) and do nothing else.
  • err != nil: resolution succeeded but opening the store failed. The caller must return err from Execute.
  • s != nil, ready == nil, err == nil: success — s is the resolved project's store and rctx its resolved context.

The vault must already exist: a path naming no vault yields an error result (vaultMissingResult) instead of a new, empty vault file — use ResolveStoreCreating for the tools that create projects.

func (*Resolver) ResolveStoreCreating

func (r *Resolver) ResolveStoreCreating(ctx context.Context, stores *store.Manager, args ContextArgs) (s *store.Store, rctx ResolvedContext, ready *ToolResult, err error)

ResolveStoreCreating is ResolveStore for tools that create the resolved project: a missing vault is created instead of reported.

type ResourceInfo added in v1.1.0

type ResourceInfo struct {
	URI         string
	Name        string
	Title       string
	Description string
}

ResourceInfo describes one concrete resource listed to clients.

type ResourceTemplate added in v1.1.0

type ResourceTemplate struct {
	URITemplate string
	Name        string
	Title       string
	Description string
}

ResourceTemplate describes one family of sync82 resources: the URI template, with {project}, {subproject} and {file} variables, and the texts shown to the client.

type Resources added in v1.1.0

type Resources struct {
	Resolver *Resolver
	Stores   *store.Manager
}

Resources serves the memory of the default vault (the one Resolver.DBPathOrDefault picks without a path) as read-only MCP resources. Reading never creates the vault and never changes the last used project.

func (*Resources) Complete added in v1.1.0

func (r *Resources) Complete(ctx context.Context, argument, value string, args map[string]string) (values []string, total int, err error)

Complete returns the values of the prompt or resource-template argument called argument that start with value (case-insensitive), from the default vault, sorted: project names for "project", the subprojects of the project in args for "subproject", and the files of that project (and subproject, when given), plus the six standard ones, for "file". It returns at most maxCompletionValues values, with the total number of matches. An unknown argument, a missing vault, or a project or subproject that doesn't exist gives no values; other store failures are returned as errors.

func (*Resources) List added in v1.1.0

func (r *Resources) List(ctx context.Context) ([]ResourceInfo, error)

List returns the context resource of every project and subproject in the default vault, in name order, or none when the vault does not exist. Store failures are returned as errors.

func (*Resources) Read added in v1.1.0

func (r *Resources) Read(ctx context.Context, uri string) (string, error)

Read returns the Markdown text of the resource at uri: the context block of load_project_context in summary mode, or the content of one file as read_memory returns it. It returns ErrResourceNotFound when uri is not a valid sync82 resource URI, the default vault does not exist, or the project, subproject or file does not; other store failures are returned as errors.

type SearchMemoryTool

type SearchMemoryTool struct {
	Resolver *Resolver
	Stores   *store.Manager
}

SearchMemoryTool implements search_memory: full-text search by words or phrase (case and Latin accents ignored, ranked by relevance), or a literal case-insensitive substring search in exact mode. Scope rule: no project → search everything; project only → that project's own documents/entries plus all its subprojects; project + subproject → that subproject only.

func (*SearchMemoryTool) Description

func (t *SearchMemoryTool) Description() string

Description returns the text shown to the calling agent that explains what the tool does and how to use it.

func (*SearchMemoryTool) Execute

func (t *SearchMemoryTool) Execute(ctx context.Context, rawArgs any) (ToolResult, error)

Execute searches the resolved scope for the query and returns the matching lines with their location, optional context and pagination hints, as text or JSON. The output is also capped in size, with the next offset reported when it is cut. A missing vault or an unusable .sync82.json yields an error result; store failures are returned as errors.

func (*SearchMemoryTool) InputSchema

func (t *SearchMemoryTool) InputSchema() map[string]any

InputSchema returns the JSON Schema of the tool's arguments: an object with the required property query, the optional properties limit, offset, context_lines and format, and the project-resolution properties.

func (*SearchMemoryTool) Name

func (t *SearchMemoryTool) Name() string

Name returns the MCP tool name, "search_memory".

func (*SearchMemoryTool) Validate

func (t *SearchMemoryTool) Validate(raw json.RawMessage) (any, error)

Validate decodes raw into searchMemoryArgs and applies the defaults (Limit 100, words match, text format), lower-casing the kinds. It returns the arguments, or an error listing every problem: an empty or multi-line query, an invalid project or subproject name, a words or phrase query with no letter or number, an unknown match, an invalid kind, since or until date, since after until, a subproject without a project, or an out-of-range limit, offset or context_lines.

type Tool

type Tool interface {
	// Name returns the tool's unique MCP name.
	Name() string
	// Description returns the text that tells the calling agent what the
	// tool does.
	Description() string

	// InputSchema must never be nil and must marshal to a JSON object
	// with "type": "object" — the SDK's Server.AddTool panics at
	// registration time otherwise (a deliberate fail-fast check so a
	// missing schema is caught at startup, not the first time an agent
	// sends bad input). A tool with no arguments still needs
	// map[string]any{"type": "object"}.
	InputSchema() map[string]any

	// Validate parses raw JSON-RPC arguments and checks them against the
	// tool's business rules (required fields, string/int bounds, enum
	// values, and so on). A non-nil error here is always a validation
	// failure, never a system error, and its message must list every
	// failing field so the calling agent can correct all of them in one
	// retry rather than discovering them one at a time.
	Validate(raw json.RawMessage) (args any, err error)

	// Execute runs the tool's business logic against the value Validate
	// returned. A non-nil error here is always an execution failure.
	Execute(ctx context.Context, args any) (ToolResult, error)
}

Tool is the interface every one of sync82's tools implements, so the server can register and dispatch all of them the same way.

Validate checks and decodes the arguments; Execute performs the call. The server (internal/server) turns an error from either one into a tool result with IsError: true, so the calling agent always sees the message — an Execute error that wraps store.ErrOpenFailed is replaced by a generic message there, since it carries low-level detail about the vault file.

Validate's returned args value is opaque to the server; only the same Tool's own Execute knows its concrete type. This type erasure is what lets internal/server hold a single []Tool of heterogeneous implementations — each tool is trusted to keep Validate and Execute in sync with each other, an invariant enforced by construction (both methods live on the same concrete type) rather than by the type system.

func Registered

func Registered(resolver *Resolver, stores *store.Manager) []Tool

Registered returns every Tool the sync82 server exposes, each wired to resolver (project resolution) and stores (vault access). It is the single list of tools the server registers.

type ToolHints added in v1.1.0

type ToolHints struct {
	Title           string
	ReadOnly        bool
	Destructive     bool
	Idempotent      bool
	ChangesProjects bool
}

ToolHints describes how a tool affects the vault, for clients deciding when to ask the user for confirmation: Title is a human-readable name, ReadOnly means the tool changes no memory, Destructive (meaningful only when not ReadOnly) that it may overwrite or delete existing memory rather than only add to it, Idempotent that repeating a call with the same arguments changes nothing more, and ChangesProjects that a successful call may create, delete or rename a project, changing the resource list. Every sync82 tool works on a closed domain (the local vault and files), never on an open world of external entities.

func HintsFor added in v1.1.0

func HintsFor(name string) (ToolHints, bool)

HintsFor returns the ToolHints of the tool called name, and whether it has any.

type ToolResult

type ToolResult struct {
	Text    string
	IsError bool
	// Structured, when set, is also returned as the result's structured
	// content (a value that marshals to a JSON object).
	Structured any
}

ToolResult is a tool's business-level outcome — the payload of a normal JSON-RPC response. Text is the message shown to the calling agent. IsError marks a failure the agent should see and act on (e.g. check_project_health reporting an unhealthy project).

type UpdateProjectMemoryTool

type UpdateProjectMemoryTool struct {
	Resolver *Resolver
	Stores   *store.Manager
}

UpdateProjectMemoryTool implements update_project_memory: save the work of a whole session in one call, appending to progress and decisions and overwriting the other standard kinds and any custom ones.

func (*UpdateProjectMemoryTool) Description

func (t *UpdateProjectMemoryTool) Description() string

Description returns the usage instructions for the calling agent.

func (*UpdateProjectMemoryTool) Execute

func (t *UpdateProjectMemoryTool) Execute(ctx context.Context, rawArgs any) (ToolResult, error)

Execute resolves the target project and applies every provided field in one transaction: all of them are written, or none is. When any field overwrites, it refuses, with an error result, a project that was only taken from the last session. A field the store state rejects (an append to a custom kind stored as a document) makes the call an error result listing every such field, with nothing written; a missing project yields the error built by wrapNotFound. It returns a plain notice when no field was provided.

func (*UpdateProjectMemoryTool) InputSchema

func (t *UpdateProjectMemoryTool) InputSchema() map[string]any

InputSchema returns the JSON Schema of the tool's arguments: an object whose properties are the project-resolution ones, one string per standard kind and a custom array of extra files.

func (*UpdateProjectMemoryTool) Name

func (t *UpdateProjectMemoryTool) Name() string

Name returns the MCP tool name, "update_project_memory".

func (*UpdateProjectMemoryTool) Validate

func (t *UpdateProjectMemoryTool) Validate(raw json.RawMessage) (any, error)

Validate decodes raw into updateProjectMemoryArgs. It lower-cases and checks the custom file names, removes entry id marker lines from every content field, and checks each provided field with the rules its write will apply (validateAppendInput for the appended ones, including the date header of progress and decisions; validateWriteInput for the overwritten ones). It returns the arguments, or an error listing every problem: too many custom items, total content over maxContentSize, a custom item naming a standard kind or with an unknown mode, or a field its write would reject — so a bad field never leaves the others half-written.

type WriteMemoryTool

type WriteMemoryTool struct {
	Resolver *Resolver
	Stores   *store.Manager
}

WriteMemoryTool implements write_memory: overwrite a memory file's entire content. It works on any kind, including the append-only ones (progress, decisions). Overwriting an append-only kind splits the incoming text into dated sections and replaces the whole entries collection; overwriting a document kind replaces it in place, keeping no history. Validation and execution delegate to validateWriteInput and writeMemoryCore, shared with update_project_memory.

func (*WriteMemoryTool) Description

func (t *WriteMemoryTool) Description() string

Description returns the text shown to the calling agent that explains what the tool does and how to use it.

func (*WriteMemoryTool) Execute

func (t *WriteMemoryTool) Execute(ctx context.Context, rawArgs any) (ToolResult, error)

Execute resolves the target project and replaces the kind's content through writeMemoryCore. It refuses, with an error result, to overwrite a project that was only taken from the last session. An unresolved project returns the instructional result; store failures, including a missing project, are returned as errors.

func (*WriteMemoryTool) InputSchema

func (t *WriteMemoryTool) InputSchema() map[string]any

InputSchema returns the JSON Schema of the tool's arguments: an object with the required properties filename and content plus the project- resolution properties.

func (*WriteMemoryTool) Name

func (t *WriteMemoryTool) Name() string

Name returns the MCP tool name, "write_memory".

func (*WriteMemoryTool) Validate

func (t *WriteMemoryTool) Validate(raw json.RawMessage) (any, error)

Validate decodes raw into writeMemoryArgs, removes entry id marker lines from content and checks filename and content with validateWriteInput. It returns the arguments with Filename normalized to its lower-case kind name, or an error listing every violated rule.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL