Documentation
¶
Overview ¶
Package notes implements a local engineering-note journal, persisted to SQLite (via GORM) under the user's application data directory.
A Note captures an engineering session or event against a project, environment, service, version, repo, branch, and set of users, with a real time range (start/stop) rather than just a duration. Notes can be searched and filtered by any of those dimensions or by free text, and the distinct values already in use for each dimension can be listed (for suggesting existing values rather than asking cold every time). A small key/value Config table lives alongside notes for remembered defaults (e.g. the project used most recently).
Notes can optionally be synced with 7pace Timetracker: pushing a note sends its date/start/stop/summary as a 7pace worklog, and pulling imports 7pace worklogs as notes. This sync is only registered when 7pace is configured (see internal/sevenpace).
The store is intentionally separate from server diagnostics: the server logs operational messages to stderr (stdout is reserved for the MCP protocol), while this package owns the user's persistent notes.
Index ¶
- Constants
- func DBPath(dataDir string) string
- func RegisterTools(s *server.Server, store *Store, sp *sevenpace.Client)
- type AddInput
- type Bucket
- type Config
- type ConfigKeyInput
- type ConfigValueOutput
- type IDInput
- type ListFilter
- type ListInput
- type ListValuesInput
- type Note
- type PullSevenPaceInput
- type PullSevenPaceOutput
- type PushSevenPaceInput
- type PushSevenPaceOutput
- type SetConfigInput
- type Store
- func (s *Store) Add(n *Note) (*Note, error)
- func (s *Store) Close() error
- func (s *Store) Delete(id uint) error
- func (s *Store) Get(id uint) (*Note, error)
- func (s *Store) GetConfig(key string) (string, error)
- func (s *Store) List(f ListFilter) ([]Note, error)
- func (s *Store) ListConfig() ([]Config, error)
- func (s *Store) ListValues(field string) ([]string, error)
- func (s *Store) SetConfig(key, value string) error
- func (s *Store) Summarize(f ListFilter) (*Summary, error)
- func (s *Store) Update(id uint, changes map[string]any) (*Note, error)
- type Summary
- type SummaryInput
- type UpdateInput
Constants ¶
const Name = "notes"
Name is the toolset name used for enable/disable filtering.
Variables ¶
This section is empty.
Functions ¶
func RegisterTools ¶
RegisterTools adds the notes toolset, backed by the SQLite store. It is a no-op when store is nil (database unavailable). sp is optional: when non-nil, the notes_push_sevenpace/notes_pull_sevenpace sync tools are also registered (see sevenpace_sync.go).
Types ¶
type AddInput ¶
type AddInput struct {
Summary string `json:"summary" jsonschema:"short summary of the session or event"`
Date string `json:"date,omitempty" jsonschema:"date YYYY-MM-DD (defaults to today)"`
Start string `json:"start,omitempty" jsonschema:"session start time, RFC3339 (e.g. 2026-01-01T09:00:00Z) (optional)"`
Stop string `json:"stop,omitempty" jsonschema:"session stop time, RFC3339 (optional)"`
Body string `json:"body,omitempty" jsonschema:"full note body, e.g. Markdown (optional)"`
Project string `json:"project,omitempty" jsonschema:"project (optional)"`
Env string `json:"env,omitempty" jsonschema:"environment, e.g. staging or production (optional)"`
Service string `json:"service,omitempty" jsonschema:"service or component name (optional)"`
Version string `json:"version,omitempty" jsonschema:"version or build identifier (optional)"`
Repo string `json:"repo,omitempty" jsonschema:"source repository (optional)"`
Branch string `json:"branch,omitempty" jsonschema:"branch name (optional)"`
Users string `json:"users,omitempty" jsonschema:"comma-separated list of users involved (optional)"`
}
AddInput records a new note.
type Bucket ¶
type Bucket struct {
Key string `json:"key" jsonschema:"the date or project this total is for"`
Notes int `json:"notes" jsonschema:"number of notes"`
Minutes int `json:"minutes" jsonschema:"total minutes (from notes with both start and stop set)"`
}
Bucket is an aggregated total for a date or project.
type Config ¶
Config is a generic key/value settings store living alongside notes, for remembered defaults (e.g. the project used most recently) so an interactive note-entry flow can suggest "same as last time?" instead of asking cold every time.
type ConfigKeyInput ¶
type ConfigKeyInput struct {
Key string `json:"key" jsonschema:"config key"`
}
ConfigKeyInput identifies a config key.
type ConfigValueOutput ¶
ConfigValueOutput wraps a single config value.
type IDInput ¶
type IDInput struct {
ID uint `json:"id" jsonschema:"note ID"`
}
IDInput identifies a note.
type ListFilter ¶
type ListFilter struct {
Date string // exact date, YYYY-MM-DD
From string // inclusive lower bound, YYYY-MM-DD
To string // inclusive upper bound, YYYY-MM-DD
Project string
Env string
Service string
Version string
Repo string
Branch string
User string // matches within the comma-separated Users list
Search string // substring match over summary or body
Limit int // max rows (default 200)
}
ListFilter scopes a List query. Empty fields are ignored.
type ListInput ¶
type ListInput struct {
Date string `json:"date,omitempty" jsonschema:"exact date YYYY-MM-DD"`
From string `json:"from,omitempty" jsonschema:"inclusive start date YYYY-MM-DD"`
To string `json:"to,omitempty" jsonschema:"inclusive end date YYYY-MM-DD"`
Project string `json:"project,omitempty" jsonschema:"exact project match (optional)"`
Env string `json:"env,omitempty" jsonschema:"exact environment match (optional)"`
Service string `json:"service,omitempty" jsonschema:"exact service match (optional)"`
Version string `json:"version,omitempty" jsonschema:"exact version match (optional)"`
Repo string `json:"repo,omitempty" jsonschema:"exact repo match (optional)"`
Branch string `json:"branch,omitempty" jsonschema:"exact branch match (optional)"`
User string `json:"user,omitempty" jsonschema:"restrict to notes whose users list contains this identity (optional)"`
Search string `json:"search,omitempty" jsonschema:"free-text substring match over summary and body (optional)"`
Limit int `json:"limit,omitempty" jsonschema:"maximum notes (default 200)"`
}
ListInput filters notes.
type ListValuesInput ¶
type ListValuesInput struct {
Field string `json:"field" jsonschema:"one of: project, env, service, version, repo, branch, users"`
}
ListValuesInput selects which field's distinct values to list.
type Note ¶
type Note struct {
ID uint `gorm:"primaryKey" json:"id"`
Date string `gorm:"index" json:"date"` // YYYY-MM-DD (defaults to today)
Start *time.Time `gorm:"index" json:"start,omitempty"`
Stop *time.Time `json:"stop,omitempty"`
Summary string `json:"summary"` // short summary of the session
Body string `json:"body,omitempty"`
Project string `gorm:"index" json:"project,omitempty"`
Env string `gorm:"index" json:"env,omitempty"`
Service string `gorm:"index" json:"service,omitempty"`
Version string `json:"version,omitempty"`
Repo string `gorm:"index" json:"repo,omitempty"`
Branch string `json:"branch,omitempty"`
// Users is a comma-separated list of user identities involved.
Users string `json:"users,omitempty"`
CreatedAt time.Time `json:"createdAt"`
UpdatedAt time.Time `json:"updatedAt"`
}
Note is a single engineering note: a session or event recorded against a project, environment, service, version, repo, branch, and set of users, with a real time range rather than just a duration.
type PullSevenPaceInput ¶
type PullSevenPaceInput struct {
Filter string `json:"filter,omitempty" jsonschema:"optional OData $filter, e.g. \"Timestamp ge 2026-01-01T00:00:00Z\""`
Top int `json:"top,omitempty" jsonschema:"maximum number of worklogs to pull (optional)"`
}
PullSevenPaceInput scopes a 7pace worklog pull.
type PullSevenPaceOutput ¶
type PullSevenPaceOutput struct {
Pulled int `json:"pulled" jsonschema:"number of worklogs fetched from 7pace"`
Created []Note `json:"created" jsonschema:"the notes created from those worklogs"`
Skipped int `json:"skipped" jsonschema:"worklogs that could not be mapped to a note, e.g. an unparseable timestamp"`
Errors []string `` /* 233-byte string literal not displayed */
}
PullSevenPaceOutput reports the notes created from a 7pace pull.
type PushSevenPaceInput ¶
type PushSevenPaceInput struct {
ID uint `json:"id" jsonschema:"note ID to push"`
WorkItemID int `json:"workItemId,omitempty" jsonschema:"linked Azure DevOps work item ID (optional; some 7pace configurations require one)"`
}
PushSevenPaceInput identifies a note to push to 7pace.
type PushSevenPaceOutput ¶
type PushSevenPaceOutput struct {
NoteID uint `json:"noteId"`
WorkLog sevenpace.Record `json:"workLog" jsonschema:"the created 7pace worklog record"`
}
PushSevenPaceOutput reports the result of pushing a note to 7pace.
type SetConfigInput ¶
type SetConfigInput struct {
Key string `json:"key" jsonschema:"config key, e.g. default_project"`
Value string `json:"value" jsonschema:"config value"`
}
SetConfigInput sets a config key/value pair.
type Store ¶
type Store struct {
// contains filtered or unexported fields
}
Store is a GORM-backed SQLite store for notes and their config.
func Open ¶
Open opens (creating if needed) the SQLite database at path and migrates the schema. GORM's own logger is silenced so it never writes to stdout, which the MCP protocol owns.
func (*Store) Delete ¶
Delete removes a note by ID. It returns gorm.ErrRecordNotFound when no note has that ID, so callers don't report a successful delete for a row that never existed (GORM itself treats a zero-row delete as success).
func (*Store) List ¶
func (s *Store) List(f ListFilter) ([]Note, error)
List returns notes matching the filter, newest date first.
func (*Store) ListConfig ¶
ListConfig returns every config key/value pair.
func (*Store) ListValues ¶
ListValues returns the distinct, sorted values already used for the given field across all notes (empty values excluded). field must be one of "project", "env", "service", "version", "repo", "branch", "users". Since Users stores a comma-separated list, its values are split before deduping.
func (*Store) SetConfig ¶
SetConfig sets (creating or overwriting) a config value. Uses an explicit upsert (not Save, which would only UPDATE since Key is a non-zero primary key and would silently affect zero rows for a key that doesn't exist yet).
type Summary ¶
type Summary struct {
Notes int `json:"notes" jsonschema:"total notes"`
TotalMinutes int `json:"totalMinutes" jsonschema:"total minutes across notes with both start and stop set"`
TotalHours float64 `json:"totalHours" jsonschema:"total hours (minutes / 60)"`
ByDate []Bucket `json:"byDate" jsonschema:"per-day totals, newest first"`
ByProject []Bucket `json:"byProject" jsonschema:"per-project totals, most minutes first"`
}
Summary aggregates notes over a date range.
type SummaryInput ¶
type SummaryInput struct {
Date string `json:"date,omitempty" jsonschema:"exact date YYYY-MM-DD"`
From string `json:"from,omitempty" jsonschema:"inclusive start date YYYY-MM-DD"`
To string `json:"to,omitempty" jsonschema:"inclusive end date YYYY-MM-DD"`
}
SummaryInput scopes a notes summary.
type UpdateInput ¶
type UpdateInput struct {
ID uint `json:"id" jsonschema:"note ID"`
Summary *string `json:"summary,omitempty" jsonschema:"new summary"`
Date *string `json:"date,omitempty" jsonschema:"new date YYYY-MM-DD"`
Start *string `json:"start,omitempty" jsonschema:"new start time, RFC3339"`
Stop *string `json:"stop,omitempty" jsonschema:"new stop time, RFC3339"`
Body *string `json:"body,omitempty" jsonschema:"new body"`
Project *string `json:"project,omitempty" jsonschema:"new project"`
Env *string `json:"env,omitempty" jsonschema:"new environment"`
Service *string `json:"service,omitempty" jsonschema:"new service"`
Version *string `json:"version,omitempty" jsonschema:"new version"`
Repo *string `json:"repo,omitempty" jsonschema:"new repo"`
Branch *string `json:"branch,omitempty" jsonschema:"new branch"`
Users *string `json:"users,omitempty" jsonschema:"new comma-separated users list"`
}
UpdateInput changes fields of a note. Pointer fields are applied only when provided, so callers can update a single field without clearing others.