Skip to content

feat(service): add Hermes-style singleton user service with lifecycle CLI - #5

Open
Martins6 wants to merge 1 commit into
mainfrom
feat/background-service-and-cli
Open

feat(service): add Hermes-style singleton user service with lifecycle CLI#5
Martins6 wants to merge 1 commit into
mainfrom
feat/background-service-and-cli

Conversation

@Martins6

Copy link
Copy Markdown
Owner

Summary

Promote Acolyte from a foreground-only bot to a per-user singleton
background service. Add public lifecycle commands, OpenCode session
wrappers, last-N log tail, strict workspace validation, persisted
workspace path, atomic runtime state, and service-aware self-update.

Command surface

  • acolyte start [--workspace PATH] — install, enable and start the per-user service.
  • acolyte stop [--forever] — stop the service; --forever disables autostart.
  • acolyte restart — restart the running service.
  • acolyte status — running/stopped + workspace + autostart (exit 3 when stopped).
  • acolyte session list / acolyte session <id>opencode session list / opencode export <id> inside the active workspace.
  • acolyte logs [N] [--date today|YYYY-MM-DD] — tail the last N application log entries (default 10).

Architecture

  • Hidden acolyte __daemon is the worker invoked by systemd (Linux) or launchd (macOS).
  • internal/service exposes a Manager interface with platform implementations selected via runtime.GOOS; service-rendered files (systemd units, plists) use text/template, never fmt.Sprintf.
  • internal/runtime writes ~/.acolyte/.service/state.json atomically with PID liveness checks (kill(pid, 0)).
  • internal/daemon wires existing bot/notifier/scheduler with proper context cancellation and Stop() hooks.
  • workspace.StrictValidate lists every missing template path and suggests acolyte new <path> instead of silently repairing.
  • cmd/update now restarts via the service manager instead of re-execing inside the same process.

PR reviewer workflow

Also adds an OpenCode-powered PR reviewer adapted from the Forge review setup:

  • .github/workflows/opencode.yml — triggers on pull_request (non-draft), issue_comment, and pull_request_review_comment; runs when the body contains /oc or /opencode.
  • .opencode/agent/pr-reviewer.md — Acolyte-aware checklist (Go module layout, Conventional Commits, gofmt/go vet/go test, cross-platform service support, no os.Exit in RunE, context-propagated exec.Command, atomic runtime-state writes).
  • .opencode/command/review.md — local /review slash command.
  • .opencode/opencode.json — model and default agent.

Verification

  • go vet ./... — clean
  • go test ./... — all packages pass
  • gofmt -l . — clean
  • GOOS=linux go build ./... and GOOS=darwin go build ./... — both succeed

Docs

  • docs/features/feat-background-service.md (new)
  • docs/features/feat-pr-reviewer.md (new)
  • docs/features/OVERVIEW.md and LOG-FEATS.md updated
  • README.md CLI table + new "Running as a background service" section

Breaking changes

  • acolyte logs DATE is replaced by acolyte logs --date DATE (default behavior is "last 10 entries").
  • acolyte start now refuses to start if the configured workspace is incomplete; run acolyte new <path> first.

… CLI

Promote Acolyte from a foreground-only bot to a per-user singleton
background service. Add public lifecycle commands, OpenCode session
wrappers, last-N log tail, strict workspace validation, persisted
workspace path, atomic runtime state, and service-aware self-update.

- cmd/start becomes the service controller (install/enable/start).
- cmd/stop [--forever], cmd/restart, cmd/status round out the lifecycle.
- Hidden acolyte __daemon is the worker invoked by systemd/launchd.
- internal/service Manager interface selects systemd (Linux) or
  launchd (macOS) at runtime via injected Runner for tests.
- internal/runtime tracks PID + readiness in
  ~/.acolyte/.service/state.json with atomic writes and kill(0)
  liveness checks.
- internal/daemon wires existing bot/notifier/scheduler/startup-check
  with proper context cancellation and Stop hooks.
- internal/opencode/session shells out to `opencode session list` and
  `opencode export <id>` inside the workspace with a LookPath guard.
- internal/logger/tail replaces the old date positional logs command
  with `acolyte logs [N] [--date today|YYYY-MM-DD]` honoring multi-line
  entries and skipping non-daily log files.
- workspace.StrictValidate lists missing template paths and suggests
  `acolyte new <path>` instead of silently repairing.
- internal/config gains LoadIfExists and WriteWorkspacePath; viper no
  longer auto-creates the singleton config during read paths.
- cmd/update now restarts through the service manager instead of
  re-execing inside the same process.

Also adds an OpenCode-powered PR reviewer workflow adapted from the
Forge review setup: .github/workflows/opencode.yml triggers on PR
events and `/oc` or `/opencode` comments, and a custom pr-reviewer
agent encodes Acolyte-specific review conventions.

Verification: go vet ./..., go test ./..., gofmt -l ., and
GOOS=linux/darwin cross-builds all succeed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant