gogents

module
v0.1.0 Latest Latest
Warning

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

Go to latest
Published: Jul 18, 2026 License: MIT

README

GoGents

CI CodeQL Go Report Card Go Reference Latest release

GoGents is an automation daemon, written in Go, that works a queue of coding tasks unattended. It continuously pulls assigned tasks from a configured source, runs an LLM coding agent (Claude Code) against them inside a prepared workspace, verifies the outcome, and reports back to wherever the task came from.

It runs standalone on your own machine: point it at a Git repository and a task source, start the daemon, and it syncs → executes → verifies → reports on a loop until you stop it.

Why GoGents

  • Unattended throughput — a long-running daemon drains a task queue on its own: it branches, runs the agent, judges the result, and reports back without a human in the loop.
  • Bring your own workflow — a workspace carries its own conventions, skills, and MCP servers (.claude/, .mcp.json). Capture a specialty once as a template and provision it repeatedly.
  • Two sources, one pipeline — feed it from GitHub Issues or from a local ticket inbox that any tool can write to; both share the same task store, state machine, and execution flow.
  • Auditable by design — a global registry tracks every runtime, and structured JSONL logs record every event, so you can inspect live state and reconstruct history after the fact.

How It Works

For each task, the daemon runs a fixed cycle:

  1. Sync — polls the configured source and claims tasks that match its filter into a shared task store.
  2. Prepare — fetches the task's content, writes it to input.md, and cuts a fresh Git branch.
  3. Execute — invokes the agent with the workspace root as its working directory, so workspace-level .claude/ and .mcp.json apply.
  4. Verify — runs the task's declared verify command (or falls back to the agent's result.json verdict) to judge pass or fail.
  5. Report — writes the outcome back to the originating source — a GitHub comment, PR link, and gogents:* label, or the ticket file's terminal status and result.
  6. Repeat on the sync interval, and shut down gracefully on SIGTERM / SIGINT.
 source ──▶ sync ──▶ task store ──▶ run agent ──▶ verify ──▶ report ──┐
    ▲                                                                 │
    └─────────────────────────── feedback ────────────────────────────┘

Task Sources

Two source types feed the one pipeline; a runtime picks one via source.type.

  • github_issue — polls GitHub Issues (via the gh CLI) by label. Feedback goes back as issue comments, PR links, and gogents:* labels.
  • local — reads a ticket inbox on disk (<GOGENTS_HOME>/tickets/ by default), claiming tickets that match the worker label and carry status: queued. On completion it writes the terminal status and result back to the ticket file.

Any tool that writes the ticket format is a producer — GoGents does not care which one. agent-manager is one such producer: it queues tickets into an inbox, points a worker's source.path at it, and later reads live execution state via gogents runtime status / gogents logs (see Managing Runtimes).

Features

  • One-Command Workspace Provisioninggogents runtime create <name> materializes a ready-to-start workspace (runtime.yaml + agent runtime elements) from a template embedded in the binary, so a downloaded binary needs no external files. Point --template at your own tree to provision a specialty repeatedly. It never deletes anything under your directory, and asks before writing into a non-empty one.
  • Pluggable Task Sourcesgithub_issue and local share one task store, state machine, and execution pipeline; a runtime selects one via source.type (see Task Sources).
  • Pluggable Agent Architecture — agents sit behind a simple probe/executor interface. Claude Code is the officially supported agent; new agents can be added by implementing the interface.
  • Ticket-Declared Verification — a local ticket may declare a verify command; the daemon runs it in the workspace and uses its exit code to judge pass/fail, falling back to the result.json coding verdict when unspecified.
  • Graceful Lifecycle Management — a signal-aware daemon with startup validation (preflight checks), crash recovery (requeues interrupted tasks), and graceful shutdown.
  • Structured Logging — JSONL-formatted logs with Asia/Taipei timezone, split into daemon.jsonl (all events) and error.jsonl (errors only).
  • Runtime Registration & Observabilitystart registers the runtime into <GOGENTS_HOME>/config.yaml (keyed by workspace path); gogents runtime list/status and gogents logs expose live runtime_state, PID, and logs for auditing.

Prerequisites

gogents runs on linux and macOS (amd64 / arm64). Windows is not supported — the daemon's process-liveness probe relies on POSIX signals.

To run gogents:

  • git
  • gh — GitHub CLI (authenticated via gh auth login)
  • Claude Code (claude) — the coding agent CLI

To build it from source, additionally:

  • Go 1.23+
  • mise — task runner & toolchain manager

Install

From a release

Install the latest release onto your PATH with one command:

curl -fsSL https://raw.githubusercontent.com/dccoding1118/gogents/main/install.sh | sh

The script detects your OS and architecture, downloads the matching archive from Releases, verifies its checksum, and installs the binary to /usr/local/bin. Override the destination with INSTALL_DIR and pin a version with VERSION:

curl -fsSL https://raw.githubusercontent.com/dccoding1118/gogents/main/install.sh \
    | VERSION=v0.1.0 INSTALL_DIR="$HOME/.local/bin" sh
Or download and install manually
VERSION=v0.1.0
OS=$(uname -s | tr '[:upper:]' '[:lower:]')   # linux | darwin
ARCH=$(uname -m | sed 's/x86_64/amd64/;s/aarch64/arm64/')

curl -fsSL -o gogents.tar.gz \
    "https://github.com/dccoding1118/gogents/releases/download/${VERSION}/gogents_${VERSION}_${OS}_${ARCH}.tar.gz"
tar -xzf gogents.tar.gz
sudo install gogents_${VERSION}_${OS}_${ARCH}/gogents /usr/local/bin/

Archives are published for linux and macOS on amd64 and arm64; the installer verifies the download against the release's checksums.txt.

The binary is self-contained: the workspace template is compiled into it, so runtime create works with nothing else installed. Each archive also carries a plain copy of templates/ for reading and copying (see Custom templates) and the LICENSE.

From source
git clone https://github.com/dccoding1118/gogents.git
cd gogents
mise install       # installs Go, golangci-lint, gofumpt
mise run build     # output: bin/gogents

Getting Started

1. Create a runtime

runtime create provisions a ready-to-start workspace from the built-in template — .gogents/runtime.yaml plus the agent runtime elements (.claude/CLAUDE.md, .claude/skills/, .mcp.json):

# Local ticket source
gogents runtime create my-worker \
    --repo https://github.com/<owner>/<repo> \
    --agent claude --model claude-sonnet-5 \
    --source local

# GitHub Issue source
gogents runtime create my-workspace \
    --repo https://github.com/<owner>/<repo> \
    --agent claude --model claude-sonnet-5 \
    --source github_issue --instance <owner>/<repo> \
    --label gogents:queued
Flag Required Default Notes
<name> yes Runtime name (positional)
--template no Template tree: a path or a name (see Custom templates); omit to use the built-in one
--workspace no ./<name> Workspace root
--repo yes Repo URL
--branch no main Default branch
--agent yes claude
--model yes Agent model
--source yes local or github_issue
--label no <name> Task filter label
--instance for github_issue <owner>/<repo>
--tickets-dir no local ticket inbox; omit to use the default
--force no false Skip the confirmation prompt on a non-empty workspace

create only builds the workspace — it does not register the runtime (that happens on start) and does not clone the repo (the daemon does that at startup). Pointing it at a non-empty directory prompts for confirmation, listing exactly what will be written or overwritten; nothing else in the directory is touched, and no file is ever deleted, including on failure. Non-interactive shells refuse instead of prompting — pass --force to proceed.

2. Run
gogents start --workspace /path/to/workspace

The daemon will:

  1. Validate config & run preflight checks (git, source toolchain, agent CLI)
  2. Initialize the workspace directory structure and register the runtime into the global registry (<GOGENTS_HOME>/config.yaml)
  3. Enter the sync loop — poll → execute → verify → report → repeat
  4. Shut down gracefully on SIGTERM / SIGINT

Global home (GOGENTS_HOME) — the global registry (config.yaml) and daemon logs (logs/<workspace-hash>/) live under a single global-home root, resolved as $GOGENTS_HOME if set, else $HOME/.gogents (default). Set GOGENTS_HOME to keep independent registries/logs on one machine (e.g. dev vs prod). The per-workspace .gogents/ (runtime.yaml / state.yaml / tasks/) is unaffected.

GOGENTS_HOME and GOGENTS_TEMPLATES are independent: the global home is a state directory for the registry and logs, and is never used as a template location.

Custom templates

The built-in template is a generic starting point. To turn a specialty — working conventions, skills, a set of MCP servers — into something you can provision repeatedly, copy templates/base/ (shipped in the release archive and in this repo), edit it, and point --template at it:

cp -r templates/base ./my-tpl
$EDITOR ./my-tpl/.claude/CLAUDE.md

gogents runtime create my-worker --template ./my-tpl \
    --repo https://github.com/<owner>/<repo> \
    --agent claude --model claude-sonnet-5 --source local

--template takes either form; the value contains a path separator ⇒ it's a path, otherwise it's a name:

--template Template tree used
./my-tpl, /opt/tpl, a/b (path) That directory. GOGENTS_TEMPLATES is ignored.
rust-svc (name), GOGENTS_TEMPLATES set $GOGENTS_TEMPLATES/rust-svc/
rust-svc (name), GOGENTS_TEMPLATES unset ./rust-svc/
omitted The template built into the binary

GOGENTS_TEMPLATES points at a directory holding your templates, one subdirectory per name — mirroring this repo's templates/ layout, so cp -r templates/base $GOGENTS_TEMPLATES/rust-svc just works:

export GOGENTS_TEMPLATES=~/gogents-templates   # holds rust-svc/, docs-writer/, …
gogents runtime create my-worker --template rust-svc --repo … --source local

It is a base for name lookups, not a search path: a single directory (not PATH-style), and it only applies to the name form. Setting it without passing --template still uses the built-in template.

A few properties worth knowing:

  • One tree wins — no layering. The resolved tree is the whole content; it is never merged with the built-in one. Dropping .mcp.json from your copy means the provisioned workspace has no .mcp.json.
  • No fallback on failure. If --template resolves to a directory that doesn't exist, create fails and tells you which path it looked at. It won't silently fall back to the built-in template and hand you a workspace that isn't what you asked for.
  • The directory you point at is the tree root. Its relative paths are the workspace's relative paths — no extra templates/ layer inside.
  • *.tmpl files are rendered through Go's text/template (the suffix is dropped); everything else is copied verbatim. Available variables: .Name, .RepoURL, .Branch, .Agent, .Model, .Source, .Label, .Instance, .TicketsPath. Referencing an unknown one is an error, not an empty string.
  • Your tree's contents aren't validated. If it renders a runtime.yaml that doesn't match the schema — or omits it entirely — you'll find out at gogents start, not at create.
Configuring manually

A workspace is just a directory with .gogents/runtime.yaml, so you can also write one by hand.

GitHub Issue source:

runtime_name: "my-workspace"
project:
  repo:
    url: "https://github.com/<owner>/<repo>"
source:
  type: "github_issue"
  instance: "<owner>/<repo>"
  filter:
    label: "gogents:queued"
  sync_interval: 30s
agent:
  type: "claude"
  model: "claude-sonnet-5"

Local ticket source:

runtime_name: "my-worker"
project:
  repo:
    url: "https://github.com/<owner>/<repo>"
source:
  type: "local"
  path: "~/.gogents/tickets"    # ticket inbox; defaults to <GOGENTS_HOME>/tickets
  filter:
    label: "<this-worker-label>"
  sync_interval: 30s
agent:
  type: "claude"
  model: "claude-sonnet-5"

Managing Runtimes

# List all registered runtimes (workspace / name / registered_at)
gogents runtime list

# Live status of one runtime (runtime_state, PID, current task, last sync);
# reports "down" if the daemon PID is no longer alive
gogents runtime status <workspace|name>

# Print a runtime's logs (daemon.jsonl / error.jsonl)
gogents logs <workspace|name>

# Unregister a retired/test runtime from the global registry (config.yaml only;
# leaves the runtime's logs and workspace .gogents/ intact, does not stop the daemon)
gogents runtime remove <workspace|name>

runtime list and runtime status accept an opt-in --json flag for a stable machine-readable contract, consumed by external tooling (agent-manager among them): a runtime array or a single status object on stdout, and a structured {"error":{"code","message"}} object on stderr with a non-zero exit on failure. Timestamps are RFC3339; an empty last_sync_at is "". Without --json the text output is unchanged.

Version
gogents version     # `gogents --version` is equivalent
gogents v0.1.0
commit:   1a2b3c4 (2026-07-17T08:30:00Z)
go:       go1.23.0
platform: darwin/arm64

Release binaries carry their tag, commit and build time, injected at build time — quote the output when reporting an issue. A binary built from source instead reports dev with the commit it was built from, suffixed -dirty if the work tree had uncommitted changes.

Contributing

GoGents is a personal tool, developed in the open as a reference. It is not accepting external pull requests, but you are welcome to fork it and take it in your own direction. Development conventions, the module map, and architecture live in AGENTS.md.

License

MIT

Directories

Path Synopsis
cmd
gogents command
internal
cli
Package cli is the command layer for the gogents binary.
Package cli is the command layer for the gogents binary.
provision
Package provision materializes a workspace from a template tree (R13 / D09).
Package provision materializes a workspace from a template tree (R13 / D09).
version
Package version resolves the identity of the running binary: the release version, source commit, build time, toolchain and target platform.
Package version resolves the identity of the running binary: the release version, source commit, build time, toolchain and target platform.
Package templates embeds the built-in workspace template tree so a `go install`-ed or downloaded binary can provision a workspace with no external files.
Package templates embeds the built-in workspace template tree so a `go install`-ed or downloaded binary can provision a workspace with no external files.

Jump to

Keyboard shortcuts

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