Documentation
¶
Overview ¶
Package centergit implements center-hosted git storage for agent and team memory — the "方案 A" of the Team 一等实体 design (docs/design/features/2026-07-12-team-entity-design.md §4.2/§4.3/§9).
The center hosts one bare git repo per agent, per team, plus a single global repo. Runtimes clone/pull/push over git's smart-HTTP protocol, reusing the center's existing per-agent bearer token for auth. This package provides:
- Host (host.go): bare-repo provisioning on the center's disk (git init --bare), per-agent / per-team / global (§4.2, §4.3 write path).
- Authorizer + TeamMembership (authz.go): the access-control decision — "does this token's agent belong to the repo's team → rw; global repo is readable by all; an agent may rw its own repo" (§9 访问控制映射). TeamMembership is the seam onto S1's team service (center maintains the agent→team mapping); a concurrency-safe in-memory MapMembership ships here for bootstrap and tests, and models "实例化时给新 agent 授权其 team repo" via Grant.
- Handler (httpbackend.go): a git smart-HTTP endpoint that authenticates the caller, authorizes read (upload-pack) vs write (receive-pack) against the requested repo, then bridges to git-http-backend via net/http/cgi.
- Store (store.go): the client-side memory store that keeps 每条经验一文件 (slug/uuid-named entry files) with a single MEMORY.md index DERIVED from the entries (never hand-edited), and pushes with pull-rebase-retry to absorb concurrent team writes (§5 渐进式加载 index, §9 并发写).
Integration note (S2 stacks on S1): wiring Handler into the admin API's router and backing TeamMembership with S1's team sqlite tables is a single step performed once S1's Team entity lands; see Handler docs for the exact AgentResolver contract against the admin auth middleware.
Index ¶
- Constants
- Variables
- func RuleAppliesToPhase(r Rule, phase string) bool
- type AgentResolver
- type Author
- type Authorizer
- type CreateMemoryProposalInput
- type Entry
- type Handler
- type HandlerOption
- type Host
- type MapMembership
- type MemoryDocument
- type MemoryItem
- type MemoryProposal
- type Operation
- type ProducerOption
- type PromoteMemoryProposalInput
- type RejectMemoryProposalInput
- type RepoKind
- type RepoRef
- type Rule
- type RuleBodySnapshot
- type RuleIndexEntry
- type RuleIndexSnapshot
- type RuleSnapshot
- type Store
- func (s *Store) Commit(ctx context.Context, author Author, message string) error
- func (s *Store) ListEntries() ([]entryIndexRow, error)
- func (s *Store) ListRules() ([]ruleIndexRow, error)
- func (s *Store) ReadEntries() (entries []Entry, skipped []string, err error)
- func (s *Store) ReadRules() (rules []Rule, skipped []string, err error)
- func (s *Store) RegenerateIndex() error
- func (s *Store) SyncPush(ctx context.Context, remote, branch string, author Author, message string, ...) error
- func (s *Store) ValidateRuleIndexBudgets() error
- func (s *Store) WriteEntry(e Entry) (string, error)
- func (s *Store) WriteRule(r Rule) (string, error)
- type StoreOption
- type TeamMembership
- type TeamMemoryConsumer
- func (c *TeamMemoryConsumer) ReadTeam(ctx context.Context, teamID string) (entries []Entry, skipped []string, err error)
- func (c *TeamMemoryConsumer) ReadTeamAllRules(ctx context.Context, teamID string) (rules []Rule, skipped []string, err error)
- func (c *TeamMemoryConsumer) ReadTeamRule(ctx context.Context, teamID, phase, slug, commit string) (RuleBodySnapshot, error)
- func (c *TeamMemoryConsumer) ReadTeamRuleIndex(ctx context.Context, teamID, phase string) (RuleIndexSnapshot, error)
- func (c *TeamMemoryConsumer) ReadTeamRules(ctx context.Context, teamID, phase string) (RuleSnapshot, error)
- type TeamMemoryProducer
- type TeamMemoryRepository
- func (r *TeamMemoryRepository) Bootstrap(ctx context.Context, teamID string, cmd TrustedBootstrapCommand) (int, string, error)
- func (r *TeamMemoryRepository) BootstrapWithPaths(ctx context.Context, teamID string, cmd TrustedBootstrapCommand) (int, []string, string, error)
- func (r *TeamMemoryRepository) Get(ctx context.Context, teamID, proposalID string) (teammemory.ProposalView, error)
- func (r *TeamMemoryRepository) List(ctx context.Context, teamID string, filter teammemory.Filter) (teammemory.ListResult, error)
- func (r *TeamMemoryRepository) Propose(ctx context.Context, teamID string, cmd teammemory.ProposeCommand) (teammemory.Result, error)
- func (r *TeamMemoryRepository) Review(ctx context.Context, teamID string, cmd teammemory.ReviewCommand) (teammemory.Result, error)
- type TeamMemoryRepositoryOption
- type TeamMemoryService
- func (s *TeamMemoryService) Configured() bool
- func (s *TeamMemoryService) CreateProposal(ctx context.Context, teamID string, in CreateMemoryProposalInput) (MemoryProposal, error)
- func (s *TeamMemoryService) GetDocument(ctx context.Context, teamID, kind, slug string) (MemoryDocument, error)
- func (s *TeamMemoryService) GetSettings(ctx context.Context, teamID string) (TeamMemorySettings, error)
- func (s *TeamMemoryService) List(ctx context.Context, teamID string) (TeamMemorySnapshot, error)
- func (s *TeamMemoryService) PromoteProposal(ctx context.Context, teamID string, in PromoteMemoryProposalInput) (MemoryProposal, error)
- func (s *TeamMemoryService) RejectProposal(ctx context.Context, teamID string, in RejectMemoryProposalInput) (MemoryProposal, error)
- func (s *TeamMemoryService) UpdateSettings(ctx context.Context, teamID string, in UpdateTeamMemorySettingsInput) (TeamMemorySettings, error)
- type TeamMemoryServiceOption
- type TeamMemorySettings
- type TeamMemorySnapshot
- type TrustedBootstrapCommand
- type UpdateTeamMemorySettingsInput
Constants ¶
const ( RuleDescriptionMaxBytes = 240 RuleIndexMaxEntries = 64 RuleIndexMaxBytes = 16 * 1024 )
const ( ProposalStatusPending = "pending" ProposalStatusPromoted = "promoted" ProposalStatusRejected = "rejected" MemoryItemEntry = "entry" MemoryItemRule = "rule" MemoryItemProposal = "proposal" MemoryItemIndex = "index" TeamMemoryEffectHint = "" /* 160-byte string literal not displayed */ )
const RuleRefreshSemantics = "" /* 200-byte string literal not displayed */
Variables ¶
var ( // ErrUnauthenticated means no agent identity was resolved from the request. ErrUnauthenticated = errors.New("centergit: unauthenticated") // ErrForbidden means the agent is known but not permitted for this repo/op. ErrForbidden = errors.New("centergit: forbidden") )
Access-control sentinels. Callers map these to HTTP 401 / 403.
var ( ErrRuleSnapshotNotFound = errors.New("rule_snapshot_not_found") ErrTeamRuleNotFound = errors.New("team_rule_not_found") ErrTeamRuleIndexTooLarge = errors.New("team_rule_index_too_large") )
var ( // ErrPushRetriesExhausted means pull-rebase-retry ran out of attempts while // racing concurrent writers. ErrPushRetriesExhausted = errors.New("centergit: push retries exhausted") // ErrInvalidEntry means an Entry failed validation. ErrInvalidEntry = errors.New("centergit: invalid entry") // ErrInvalidRule means a Rule failed validation. ErrInvalidRule = errors.New("centergit: invalid rule") )
Store errors.
var ( ErrTeamMemoryNotConfigured = errors.New("team memory: service not configured") ErrTeamMemoryNotFound = errors.New("team memory: not found") ErrTeamMemoryInvalidProposal = errors.New("team memory: invalid proposal") ErrTeamMemoryProposalNotPending = errors.New("team memory: proposal is not pending") ErrTeamMemoryWarningAckRequired = errors.New("team memory: warning acknowledgement required") ErrTeamMemoryAgentSelfGrant = errors.New("team memory: agents cannot self-grant curator access") ErrTeamMemoryInvalidSettings = errors.New("team memory: invalid settings") )
var ErrGitOpFailed = errors.New("centergit: git operation failed")
ErrGitOpFailed wraps a failed git plumbing invocation.
var ErrHostRootEmpty = errors.New("centergit: host root is empty")
ErrHostRootEmpty is returned when a Host is constructed without a root dir.
var ErrInvalidRepoRef = errors.New("centergit: invalid repo ref")
ErrInvalidRepoRef is returned for a malformed or unsafe RepoRef.
Functions ¶
func RuleAppliesToPhase ¶
RuleAppliesToPhase reports whether r is enabled and active in phase.
Types ¶
type AgentResolver ¶
AgentResolver extracts the authenticated agent id from a request. In the admin API this is backed by the bearer-token auth middleware: resolve the worker token → the operating agent (requireAgentOnWorker) → agent.ID(). It returns ok=false when no agent identity is present (→ HTTP 401).
type Authorizer ¶
type Authorizer struct {
// contains filtered or unexported fields
}
Authorizer decides whether an authenticated agent may read/write a repo, implementing the §4.2/§9 rules:
- global repo : read = every authenticated agent; write = forbidden (platform-level, not agent-writable).
- agent repo : rw iff the requesting agent owns the repo.
- team repo : rw iff the agent's team == the repo's team.
func NewAuthorizer ¶
func NewAuthorizer(m TeamMembership) *Authorizer
NewAuthorizer wires an Authorizer over a TeamMembership source.
type Entry ¶
type Entry struct {
// Slug is the human, path-safe stem of the file name (e.g.
// "prefer-table-driven-tests"). Combined with a uuid it forms the file name.
Slug string
// Title is an optional heading for the entry body.
Title string
// Description is the one-line hook that lands in the index.
Description string
// Body is the markdown content (without frontmatter).
Body string
// Type is an optional classification (user/feedback/project/reference…).
Type string
// SourcePath is populated by readers with the repo-relative path.
SourcePath string
// UUID is populated by readers from the entry frontmatter.
UUID string
}
Entry is one memory experience. Design §9 mandates 每条经验一文件 so concurrent writers touch different files (git auto-merges), and the shared MEMORY.md index is DERIVED from entries — never hand-edited.
type Handler ¶
type Handler struct {
// contains filtered or unexported fields
}
Handler is the center-hosted git smart-HTTP endpoint (§4.2/§4.3). Per request it: (1) resolves the caller's agent id, (2) parses the target RepoRef and whether the operation reads (upload-pack) or writes (receive-pack), (3) authorizes via Authorizer, then (4) bridges to git-http-backend over CGI.
Mount it behind the admin auth+deps middleware, e.g. at "/admin/git/"; set MountPrefix to that value so the handler can recover the bare repo path.
func NewHandler ¶
func NewHandler(host *Host, authz *Authorizer, resolve AgentResolver, opts ...HandlerOption) (*Handler, error)
NewHandler wires a Handler. When the git-http-backend path is not overridden it is discovered via `git --exec-path`.
type HandlerOption ¶
type HandlerOption func(*Handler)
HandlerOption configures a Handler.
func WithExtraEnv ¶
func WithExtraEnv(env ...string) HandlerOption
WithExtraEnv appends env vars to every CGI invocation.
func WithHTTPBackend ¶
func WithHTTPBackend(path string) HandlerOption
WithHTTPBackend overrides the git-http-backend binary path (tests / non-default git installs).
func WithMountPrefix ¶
func WithMountPrefix(p string) HandlerOption
WithMountPrefix sets the URL prefix the handler is mounted at; it is trimmed from the request path before the repo path is parsed.
type Host ¶
type Host struct {
// contains filtered or unexported fields
}
Host owns the center's bare-repo tree: one bare repo per agent / team plus a single global repo, all under root (§4.2 "center 每个 agent/team 建一个 bare repo 在自己盘上"). It is the provisioning surface — runtimes never touch these dirs directly, they clone/push over the smart-HTTP Handler.
func (*Host) EnsureRepo ¶
EnsureRepo idempotently provisions ref's bare repo: git init --bare (initial branch main) plus http.receivepack=true so authenticated push works over smart-HTTP. Provisioning per-agent / per-team repos and, at instantiation, a team's shared repo, all funnel through here (§4.2/§4.3, §9 provisioning).
func (*Host) RepoExists ¶
RepoExists reports whether ref's bare repo has been provisioned (probed via the presence of its HEAD file, which git init --bare always writes).
type MapMembership ¶
type MapMembership struct {
// contains filtered or unexported fields
}
MapMembership is a concurrency-safe in-memory TeamMembership. It also models "实例化时给新 agent 授权其 team repo" (§9): instantiation calls Grant to record the new agent's team, which immediately unlocks rw on that team's repo.
func NewMapMembership ¶
func NewMapMembership() *MapMembership
NewMapMembership returns an empty membership map.
func (*MapMembership) Grant ¶
func (m *MapMembership) Grant(agentID, teamID string)
Grant records that agentID belongs to teamID (agent 独占一个 team — this overwrites any prior team for the agent).
func (*MapMembership) Revoke ¶
func (m *MapMembership) Revoke(agentID string)
Revoke removes the agent's team membership.
func (*MapMembership) TeamOfAgent ¶
TeamOfAgent implements TeamMembership.
type MemoryDocument ¶
type MemoryItem ¶
type MemoryProposal ¶
type MemoryProposal struct {
ID string
UUID string
Status string
TargetKind string
Slug string
Title string
Description string
Body string
AuthorRef string
CreatedAt string
UpdatedAt string
SourcePath string
PromotedPath string
TargetUUID string
Commit string
Enabled bool
AppliesTo []string
WarningAcknowledged bool
RejectReason string
Diff string
}
type Operation ¶
type Operation int
Operation is a smart-HTTP access mode: OpRead (git-upload-pack / clone / pull) or OpWrite (git-receive-pack / push).
type ProducerOption ¶
type ProducerOption func(*TeamMemoryProducer)
ProducerOption configures a TeamMemoryProducer.
func WithSeedAuthor ¶
func WithSeedAuthor(a Author) ProducerOption
WithSeedAuthor overrides the git author the seed commit is attributed to.
type RepoKind ¶
type RepoKind string
RepoKind enumerates the three center-hosted git repo scopes (§4.2).
const ( // RepoKindAgent is a single agent's private memory repo. RepoKindAgent RepoKind = "agent" // RepoKindTeam is a team's shared memory repo (all members rw). RepoKindTeam RepoKind = "team" // RepoKindGlobal is the single platform-level repo (all agents read). RepoKindGlobal RepoKind = "global" )
type RepoRef ¶
RepoRef identifies one bare repo on the center host. For RepoKindGlobal the ID is empty (there is exactly one global repo).
type Rule ¶
type Rule struct {
// Slug is the human, path-safe stem of the file name.
Slug string
// Title is an optional heading for the rule body.
Title string
// Description is the one-line hook that lands in the index.
Description string
// Body is the markdown content (without frontmatter).
Body string
// Enabled gates whether the rule is loaded into runtime context.
Enabled bool
// AppliesTo names the phases where the rule is active. Empty normalizes to
// all phases when writing; accepted values are plan, execute, review,
// recovery, or all.
AppliesTo []string
// SourcePath is populated by readers with the repo-relative path.
SourcePath string
// UUID is populated by readers from the rule frontmatter.
UUID string
}
Rule is one team-scoped operational rule. Rules live under rules/; that directory, not a frontmatter kind, is the only source of their type.
type RuleBodySnapshot ¶
type RuleBodySnapshot struct {
TeamID string
Phase string
Commit string
Rule Rule
RefreshSemantics string
}
RuleBodySnapshot records one commit-bound rule body read.
type RuleIndexEntry ¶
type RuleIndexEntry struct {
Slug string `json:"slug"`
Title string `json:"title,omitempty"`
Description string `json:"description"`
AppliesTo []string `json:"applies_to"`
BodyBytes int `json:"body_bytes"`
SourcePath string `json:"source_path,omitempty"`
}
RuleIndexEntry is the body-free startup/runtime projection for one rule.
type RuleIndexSnapshot ¶
type RuleIndexSnapshot struct {
TeamID string
Phase string
Commit string
Rules []RuleIndexEntry
Skipped []string
RefreshSemantics string
}
RuleIndexSnapshot records the exact commit used to build a phase-scoped index.
type RuleSnapshot ¶
type RuleSnapshot struct {
TeamID string
Phase string
Commit string
Rules []Rule
Skipped []string
RefreshSemantics string
}
RuleSnapshot is the auditable result of loading team rules from a repo commit.
type Store ¶
type Store struct {
// contains filtered or unexported fields
}
Store is the client-side (runtime) view of a checked-out center repo working copy. It writes per-entry files, regenerates the index deterministically, and pushes with pull-rebase-retry to absorb concurrent team writes (§5, §9).
func NewStore ¶
func NewStore(dir string, runner memory.GitRunner, opts ...StoreOption) *Store
NewStore wires a Store over the working-copy dir. A nil runner defaults to the real git binary; the default uuid source is a ULID.
func (*Store) Commit ¶
Commit stages the whole working tree and commits under author. It is a no-op (returns nil) when the tree is clean.
func (*Store) ListEntries ¶
ListEntries parses every entries/*.md file's frontmatter. Entries are sorted by (name, file) for a stable, deterministic order.
func (*Store) ListRules ¶
ListRules parses every rules/*.md file's frontmatter. Rules are sorted by (name, file) for a stable, deterministic order.
func (*Store) ReadEntries ¶
ReadEntries parses every entries/*.md file into a FULL Entry (frontmatter + body + type). Unlike ListEntries — which yields only the index projection (name/description/file) — this reconstructs each experience so a caller such as extract_from_team can carry it into a draft template. Sorted by (slug, file) for a deterministic order.
DEFENSIVE (design §6 extract): a team member may push ANY non-standard / stray file into the shared team repo (a note without frontmatter, a scratch file, …). A single malformed file must NOT crash the whole extract. Such files are SKIPPED and their names returned in `skipped` so the caller can flag "skipped N non-standard entries" in the draft/response for the curator. Only a genuine IO error (not a content-format problem) surfaces as an error. This read path is deliberately lenient; the WRITE-side index derivation (ListEntries / RegenerateIndex) stays strict — a writer controls its own files.
func (*Store) ReadRules ¶
ReadRules parses every rules/*.md file into a FULL Rule. Malformed rule files are skipped and returned to the caller; genuine IO errors surface.
func (*Store) RegenerateIndex ¶
RegenerateIndex rebuilds MEMORY.md purely from entries/ and rules/ (§9: 索引从条目派生、不手编). The output is deterministic so identical memory sets on two runtimes produce byte-identical indexes → no spurious merge conflicts.
func (*Store) SyncPush ¶
func (s *Store) SyncPush(ctx context.Context, remote, branch string, author Author, message string, maxRetries int) error
SyncPush regenerates the index, commits, then pushes to remote/branch. On a non-fast-forward rejection (a concurrent team writer landed first) it runs pull --rebase and retries, up to maxRetries times — the §9 "push 前 pull-rebase-retry 兜并发写" contract. Because entries are per-file, the rebase almost never conflicts; only the derived index could, and it is regenerated deterministically after each rebase.
func (*Store) ValidateRuleIndexBudgets ¶
ValidateRuleIndexBudgets enforces the phase-scoped rule-index budget that new runtime contexts depend on. It reads complete rule bodies so body_bytes is accurate, but does not persist or mutate anything.
func (*Store) WriteEntry ¶
WriteEntry persists e as entries/<slug>-<uuid>.md and returns the repo-relative path. It does NOT commit or regenerate the index — callers batch those (see RegenerateIndex + SyncPush) so a burst of writes is one commit.
type StoreOption ¶
type StoreOption func(*Store)
StoreOption configures a Store.
func WithHomeOverride ¶
func WithHomeOverride(home string) StoreOption
WithHomeOverride sets HOME/XDG_CONFIG_HOME for git invocations (test hygiene).
func WithIDGen ¶
func WithIDGen(fn func() string) StoreOption
WithIDGen injects the entry uuid generator (tests use a deterministic one).
type TeamMembership ¶
type TeamMembership interface {
// TeamOfAgent returns the team the agent belongs to. ok=false means the
// agent is in no team (yet). err is reserved for backing-store failures.
TeamOfAgent(ctx context.Context, agentID string) (teamID string, ok bool, err error)
}
TeamMembership is the seam onto S1's team service: the center maintains the agent→team mapping and this port answers "which team does this agent belong to" (§9 访问控制映射). An agent 独占一个 team, so at most one team id.
S1's Team entity backs this with sqlite; S2 ships MapMembership for bootstrap and tests.
type TeamMemoryConsumer ¶
type TeamMemoryConsumer struct {
// contains filtered or unexported fields
}
TeamMemoryConsumer reads a team's center-hosted memory repo.
func NewTeamMemoryConsumer ¶
func NewTeamMemoryConsumer(host *Host, runner memory.GitRunner) *TeamMemoryConsumer
NewTeamMemoryConsumer wires a consumer over host. A nil runner defaults to the real git binary (memory.NewExecGitRunner).
func (*TeamMemoryConsumer) ReadTeam ¶
func (c *TeamMemoryConsumer) ReadTeam(ctx context.Context, teamID string) (entries []Entry, skipped []string, err error)
ReadTeam clones team teamID's bare repo into a throwaway working copy and returns every memory entry (frontmatter + body). A team whose repo has not been provisioned yet (no memory seeded) yields nil, nil, nil — an absent history is not an error, it is simply an empty experience set.
The returned `skipped` list names any non-standard files in the repo that are NOT well-formed memory entries (no frontmatter, etc.): they are skipped rather than crashing the read, so a member's stray push cannot break extract_from_team (design §6). Callers surface the count for the curator.
func (*TeamMemoryConsumer) ReadTeamAllRules ¶
func (c *TeamMemoryConsumer) ReadTeamAllRules(ctx context.Context, teamID string) (rules []Rule, skipped []string, err error)
ReadTeamAllRules returns every rule file regardless of enabled/applies_to. It is used by extract/template flows; runtime context should use ReadTeamRules so disabled or non-matching rules do not leak into a run.
func (*TeamMemoryConsumer) ReadTeamRule ¶
func (c *TeamMemoryConsumer) ReadTeamRule(ctx context.Context, teamID, phase, slug, commit string) (RuleBodySnapshot, error)
ReadTeamRule reads one enabled, phase-applicable rule body from the exact commit supplied by a prior index response. It never falls back to HEAD.
func (*TeamMemoryConsumer) ReadTeamRuleIndex ¶
func (c *TeamMemoryConsumer) ReadTeamRuleIndex(ctx context.Context, teamID, phase string) (RuleIndexSnapshot, error)
ReadTeamRuleIndex returns a body-free, phase-scoped rule index from the team's current HEAD commit. A missing team repo yields an empty snapshot. Malformed rule files are skipped and reported.
func (*TeamMemoryConsumer) ReadTeamRules ¶
func (c *TeamMemoryConsumer) ReadTeamRules(ctx context.Context, teamID, phase string) (RuleSnapshot, error)
ReadTeamRules clones team teamID's bare repo into a throwaway working copy and returns the enabled rules that apply to phase plus the exact HEAD commit used. A missing team repo yields an empty snapshot, not an error. Malformed rule files are skipped and reported, mirroring ReadTeam's defensive contract.
type TeamMemoryProducer ¶
type TeamMemoryProducer struct {
// contains filtered or unexported fields
}
TeamMemoryProducer seeds a team's center-hosted memory repo from a set of portable experiences. It owns no state beyond the Host it provisions against and the git runner it drives.
func NewTeamMemoryProducer ¶
func NewTeamMemoryProducer(host *Host, runner memory.GitRunner, opts ...ProducerOption) *TeamMemoryProducer
NewTeamMemoryProducer wires a producer over host. A nil runner defaults to the real git binary (memory.NewExecGitRunner).
func (*TeamMemoryProducer) SeedTeam ¶
func (p *TeamMemoryProducer) SeedTeam(ctx context.Context, teamID string, entries []Entry, ruleSets ...[]Rule) (int, error)
SeedTeam provisions (idempotently) team teamID's bare repo and writes each entry/rule into it as one file, pushing a single seed commit. Entries/rules that fail per-item validation are skipped — seeding is best-effort over a human-curated template. Returns the number of items actually written. A nil/zero item set is a no-op (repo still provisioned). The variadic rules parameter preserves the original entries-only call shape.
type TeamMemoryRepository ¶
type TeamMemoryRepository struct {
// contains filtered or unexported fields
}
TeamMemoryRepository is the Git-backed Repository adapter for ADR-0057. Each command uses a fresh clone of the team's bare repo, and the pushed main HEAD is the aggregate version.
func NewTeamMemoryRepository ¶
func NewTeamMemoryRepository(host *Host, runner memory.GitRunner, opts ...TeamMemoryRepositoryOption) *TeamMemoryRepository
NewTeamMemoryRepository wires the Git-backed Team Memory repository.
func (*TeamMemoryRepository) Bootstrap ¶
func (r *TeamMemoryRepository) Bootstrap(ctx context.Context, teamID string, cmd TrustedBootstrapCommand) (int, string, error)
Bootstrap applies trusted seed content to canonical memory. It exists so Producer/migration do not keep a separate long-term Store bypass.
func (*TeamMemoryRepository) BootstrapWithPaths ¶
func (r *TeamMemoryRepository) BootstrapWithPaths(ctx context.Context, teamID string, cmd TrustedBootstrapCommand) (int, []string, string, error)
BootstrapWithPaths is the detailed form used by migrations that must report exact rollback paths.
func (*TeamMemoryRepository) Get ¶
func (r *TeamMemoryRepository) Get(ctx context.Context, teamID, proposalID string) (teammemory.ProposalView, error)
Get reads one proposal by id from one team repo.
func (*TeamMemoryRepository) List ¶
func (r *TeamMemoryRepository) List(ctx context.Context, teamID string, filter teammemory.Filter) (teammemory.ListResult, error)
List returns proposals in the team repo. Default status is pending.
func (*TeamMemoryRepository) Propose ¶
func (r *TeamMemoryRepository) Propose(ctx context.Context, teamID string, cmd teammemory.ProposeCommand) (teammemory.Result, error)
Propose writes a pending proposal under proposals/ and pushes it. Concurrent unrelated proposals retry from a fresh clone so both commits survive without last-write-wins.
func (*TeamMemoryRepository) Review ¶
func (r *TeamMemoryRepository) Review(ctx context.Context, teamID string, cmd teammemory.ReviewCommand) (teammemory.Result, error)
Review promotes or rejects one pending proposal. Promotion updates canonical memory, proposal status, and MEMORY.md in one commit; push races return a fail-loud version conflict.
type TeamMemoryRepositoryOption ¶
type TeamMemoryRepositoryOption func(*TeamMemoryRepository)
TeamMemoryRepositoryOption configures the Git repository adapter.
func WithProposalIDGen ¶
func WithProposalIDGen(fn func() string) TeamMemoryRepositoryOption
WithProposalIDGen injects deterministic proposal ids for tests. The function may return either a bare id or a tmprop- prefixed id.
func WithRepositoryAuthor ¶
func WithRepositoryAuthor(a Author) TeamMemoryRepositoryOption
WithRepositoryAuthor overrides the stable system git identity.
func WithRepositoryClock ¶
func WithRepositoryClock(fn func() time.Time) TeamMemoryRepositoryOption
WithRepositoryClock injects deterministic timestamps.
type TeamMemoryService ¶
type TeamMemoryService struct {
// contains filtered or unexported fields
}
func NewTeamMemoryService ¶
func NewTeamMemoryService(host *Host, runner memory.GitRunner, opts ...TeamMemoryServiceOption) *TeamMemoryService
func (*TeamMemoryService) Configured ¶
func (s *TeamMemoryService) Configured() bool
func (*TeamMemoryService) CreateProposal ¶
func (s *TeamMemoryService) CreateProposal(ctx context.Context, teamID string, in CreateMemoryProposalInput) (MemoryProposal, error)
func (*TeamMemoryService) GetDocument ¶
func (s *TeamMemoryService) GetDocument(ctx context.Context, teamID, kind, slug string) (MemoryDocument, error)
func (*TeamMemoryService) GetSettings ¶
func (s *TeamMemoryService) GetSettings(ctx context.Context, teamID string) (TeamMemorySettings, error)
func (*TeamMemoryService) List ¶
func (s *TeamMemoryService) List(ctx context.Context, teamID string) (TeamMemorySnapshot, error)
func (*TeamMemoryService) PromoteProposal ¶
func (s *TeamMemoryService) PromoteProposal(ctx context.Context, teamID string, in PromoteMemoryProposalInput) (MemoryProposal, error)
func (*TeamMemoryService) RejectProposal ¶
func (s *TeamMemoryService) RejectProposal(ctx context.Context, teamID string, in RejectMemoryProposalInput) (MemoryProposal, error)
func (*TeamMemoryService) UpdateSettings ¶
func (s *TeamMemoryService) UpdateSettings(ctx context.Context, teamID string, in UpdateTeamMemorySettingsInput) (TeamMemorySettings, error)
type TeamMemoryServiceOption ¶
type TeamMemoryServiceOption func(*TeamMemoryService)
func WithTeamMemoryClock ¶
func WithTeamMemoryClock(fn func() time.Time) TeamMemoryServiceOption
func WithTeamMemoryIDGen ¶
func WithTeamMemoryIDGen(fn func() string) TeamMemoryServiceOption
type TeamMemorySettings ¶
type TeamMemorySnapshot ¶
type TeamMemorySnapshot struct {
TeamID string
Commit string
Entries []MemoryItem
Rules []MemoryItem
Proposals []MemoryProposal
Skipped []string
EffectHint string
RefreshSemantics string
}
type TrustedBootstrapCommand ¶
TrustedBootstrapCommand is the non-MCP/non-Web path used only for team instantiate and one-time legacy migration. It writes canonical memory without proposals, under the stable system Git author.