setup

package
v0.1.2 Latest Latest
Warning

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

Go to latest
Published: Aug 3, 2026 License: MIT Imports: 5 Imported by: 0

Documentation

Overview

Package setup installs the Claude Code Skill bundle that ADR-0002 decided on, so that Claude Code knows when and how to invoke the syntropy binary.

This is deliberately Claude-only for now: ADR-0002 picked the Skill bundle as the first integration, not the only one. syntropy's Runner interface (ADR-0007) already anticipates other coding agents (Codex, Qwen, OpenHands, ...); adding one there needs a companion integration bundle in that agent's own distribution format, added alongside this package rather than folded into it.

Index

Constants

View Source
const BlankSentinel = "blank"

BlankSentinel is written to a RepoConfig field, instead of leaving it as an empty string or omitting it, when the user was explicitly asked and chose not to set a value. Plain "" is ambiguous between "never asked" and "asked, declined" — every field in this file needs a way to distinguish the two so an agent following the syntropy Skill knows whether to ask again, and so new fields added in a later syntropy version are correctly recognised as unasked (empty) even in an existing repo's .syntropy.yml, rather than mistaken for a deliberate blank.

Variables

View Source
var KnownRunners = []string{"claude"}

KnownRunners lists the coding-agent runners `everflow setup` can offer as a default. Mirrors the runners actually registered in main() (ADR-0007) — "claude" is the only one today. Kept here rather than introspecting a live runner.Registry so setup can validate --runner and auto-select a default without constructing runners (and their subprocess dependencies) just to list their names.

Functions

func EnsureClaudeSkill

func EnsureClaudeSkill(home string) (bool, error)

EnsureClaudeSkill installs ~/.claude/skills/syntropy/SKILL.md the first time it's called on a host that has Claude Code set up (~/.claude/ present). It's a no-op if Claude Code isn't installed, or if the skill file already exists — the file's own presence is the marker, so a user's local edits to it are never overwritten by a later invocation. It reports whether it installed the file, so callers can surface a one-time summary.

func InstallClaudeSkill

func InstallClaudeSkill(home string, force bool) (bool, error)

InstallClaudeSkill installs the Skill bundle for the explicit `syntropy setup` command. Unlike EnsureClaudeSkill it doesn't require ~/.claude to already exist — an explicit setup request creates it. When force is true, an existing Skill file is overwritten; otherwise install is skipped and the existing file is left untouched.

func MissingFields

func MissingFields(cfg RepoConfig) []string

MissingFields returns the names of every recognised RepoConfig field that hasn't been decided yet (see IsConfigured) — i.e. that an agent following the syntropy Skill should ask the user about. Pure, cheap, deterministic: no LLM invocation needed to answer "is this repo fully configured" (ADR-0083) — CheckRepoConfig/`syntropy config check` calls this so an agent can gate a conversational ask on its output instead of reading and reasoning about the YAML file itself every time.

Add a case here for every new field RepoConfig grows — this is the one place the "which fields exist" list needs to stay current.

func RepoConfigPath

func RepoConfigPath(repoDir string) string

RepoConfigPath returns the `.syntropy.yml` path for the given repo root.

func ResolveModel

func ResolveModel(flagModel, existing string, interactive bool, prompt func(existing string) (string, error)) (string, error)

ResolveModel picks the default model `everflow setup` should persist. Precedence: --model flag, then (if interactive) the prompt's answer, then the existing persisted value — so a non-interactive re-run (no TTY, no flag; e.g. from a script or cron) leaves a previously configured model untouched rather than clobbering it back to empty.

prompt is called only when flagModel is empty and interactive is true; it receives the existing value to show as the default and returns the raw (untrimmed-by-caller) line the user typed, or an error reading stdin.

func ResolveRunner

func ResolveRunner(flagRunner string) (string, error)

ResolveRunner picks the runner `everflow setup` should persist as the default. flagRunner is whatever --runner was passed (empty if not set).

With only one KnownRunners entry, an unset flag auto-selects it — there's nothing to choose between yet. A set flag is validated against KnownRunners so a typo (or a not-yet-supported agent name) fails loudly instead of getting silently persisted.

func ResolveTitleConvention

func ResolveTitleConvention(flagConvention string, interactive bool, prompt func() (string, error)) (string, error)

ResolveTitleConvention picks the free-text title convention `syntropy setup` should write to `.syntropy.yml`. Precedence: --title-convention flag, then (if interactive) the prompt's answer, then empty — a non-interactive run with no flag makes no claim about a convention rather than guessing one.

prompt is called only when flagConvention is empty and interactive is true; it returns the raw line the user typed, or an error reading stdin.

func SkillPath

func SkillPath(home string) string

SkillPath returns the path where the Claude Code Skill bundle lives under the given home directory.

func WriteRepoConfig

func WriteRepoConfig(repoDir, convention string, force bool) (bool, error)

WriteRepoConfig writes `.syntropy.yml` into repoDir with the given title convention. It's a no-op (returns false, nil) when convention is empty — there's nothing to persist — or when the file already exists and force is false, so a user's local edits to it are never clobbered by a later `syntropy setup` run.

Types

type RepoConfig

type RepoConfig struct {
	// TitleConvention is free-text guidance on how this repo likes its
	// PR/MR titles phrased, e.g. "Conventional Commits" or "ticket ID
	// prefix like PROJ-123: ...". Empty means the field is missing from
	// the file entirely — this repo has never been asked (e.g. an older
	// .syntropy.yml predating this field, or the file doesn't exist at
	// all) — an agent following the syntropy Skill should ask the user
	// and persist an answer. BlankSentinel means the user WAS asked and
	// deliberately chose not to set one — don't ask again, and don't
	// treat it as a convention to inject anywhere (see
	// EffectiveTitleConvention).
	TitleConvention string `yaml:"title_convention"`
}

RepoConfig is the on-disk shape of `.syntropy.yml`, a per-repo (not per-user) config file living at the root of a spec's `base_repo`.

func ReadRepoConfig

func ReadRepoConfig(repoDir string) (RepoConfig, error)

ReadRepoConfig reads `.syntropy.yml` from repoDir, returning a zero-value RepoConfig (no error) if the file doesn't exist — absence means "no convention set", not a failure. Mirrors WriteRepoConfig's file-presence convention (ADR-0052).

func (RepoConfig) EffectiveTitleConvention

func (c RepoConfig) EffectiveTitleConvention() string

EffectiveTitleConvention returns the value to actually use when building a runner prompt: the real convention if one was set, or "" for both "never asked" and BlankSentinel — callers that gate a prompt block on non-empty (e.g. the runner's `if req.TitleConvention != ""`) should call this rather than reading TitleConvention directly, so BlankSentinel never leaks into prompt text verbatim.

func (RepoConfig) IsConfigured

func (c RepoConfig) IsConfigured() bool

IsConfigured reports whether TitleConvention has been decided at all — either a real convention or an explicit BlankSentinel — as opposed to being absent, which means an agent following the syntropy Skill should ask the user for it.

Jump to

Keyboard shortcuts

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