Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

hyperifyio/goagent

Repository files navigation

goagent — Minimal, safe, non‐interactive agent CLI

CI (lint+test+build) Go Version Go Reference Release License: MIT

goagent is a compact, vendor‐agnostic command‐line tool for running non‐interactive, tool‐using agents against any OpenAI‐compatible Chat Completions API. It executes a small, auditable allowlist of local tools (argv only; no shell), streams JSON in/out, and prints a concise final answer.

  • Why use it: deterministic, portable, and safe by default. Works with hosted providers and with local endpoints like http://localhost:1234/v1.
  • Who it’s for: engineers who want a minimal agent runner with clear guarantees and zero vendor lock‐in.
  • What makes it different: strict "argv‐only" tool execution, explicit allowlists, and a pragmatic default LLM policy for predictable behavior across providers.

Table of contents

At a glance

  • Minimal, portable, vendor‐agnostic: works with any OpenAI‐compatible endpoint
  • Deterministic and auditable: argv‐only tool execution, JSON stdin/stdout, strict timeouts
  • Safe by default: explicit allowlist of tools; no shell evaluation
  • Batteries included: a small toolbelt for filesystem, process, network, and image tasks

Features

  • OpenAI‐compatible POST /v1/chat/completions via net/http (no SDK)
  • Explicit tools allowlist: tools.json with JSON Schema parameters (see Tools manifest reference)
  • Deterministic execution: argv‐only tools, JSON stdin/stdout, per‐call timeouts
  • Predictable error surface: tool errors mapped as structured JSON
  • Observability & hygiene: audit logging with redaction; transcript size controls

Installation

Requirements

  • Go 1.24+ on Linux, macOS, or Windows
  • Network access to an OpenAI‐compatible API
  • For development and examples: ripgrep (rg), jq, and golangci-lint

Install options

  1. Download a binary: see Releases

  2. With Go (adds agentcli to your GOBIN):

go install github.com/hyperifyio/goagent/cmd/agentcli@latest
  1. Build from source:
git clone https://github.com/hyperifyio/goagent
cd goagent
make bootstrap tidy build build-tools

Verify installation:

./bin/agentcli --version

Developer prerequisites (examples):

# ripgrep
# - Ubuntu/Debian
sudo apt-get update && sudo apt-get install -y ripgrep
# - macOS (Homebrew)
brew install ripgrep
# - Windows (Chocolatey)
choco install ripgrep -y
# golangci-lint (pinned; installs into ./bin via Makefile)
make install-golangci
./bin/golangci-lint version
# jq (used by examples and runbooks)
# - Ubuntu/Debian
sudo apt-get install -y jq
# - macOS (Homebrew)
brew install jq
# - Windows (Chocolatey)
choco install jq -y
# make (Windows, for running Makefile targets used in docs)
# - Windows (Chocolatey)
choco install make -y

Configuration

Configuration precedence is: flags > environment > built‐in defaults.

Environment variables:

  • OAI_BASE_URL — API base (default https://api.openai.com/v1). Helper scripts will also read LLM_BASE_URL if present.
  • OAI_MODEL — model ID (default oss-gpt-20b). Helper scripts will also read LLM_MODEL if present.
  • OAI_API_KEY — API key when required. The CLI also accepts OPENAI_API_KEY for compatibility.
  • OAI_HTTP_TIMEOUT — HTTP timeout for chat requests (e.g., 90s). Mirrors -http-timeout. OAI_PREP_HTTP_TIMEOUT — HTTP timeout for pre-stage; overrides inheritance from -http-timeout.

Inheritance and precedence

The CLI resolves values independently for chat (main), pre-stage, and image flows, with inheritance when explicit values are not provided.

Endpoints and API keys:

Setting Resolution order
Chat base URL -base-urlOAI_BASE_URL → default https://api.openai.com/v1
Pre-stage base URL -prep-base-urlOAI_PREP_BASE_URL → inherit Chat base URL
Image base URL -image-base-urlOAI_IMAGE_BASE_URL → inherit Chat base URL
Chat API key -api-keyOAI_API_KEYOPENAI_API_KEY
Pre-stage API key -prep-api-keyOAI_PREP_API_KEY → inherit Chat API key
Image API key -image-api-keyOAI_IMAGE_API_KEY → inherit Chat API key

Models and sampling:

Setting Resolution order
Chat model -modelOAI_MODEL → default oss-gpt-20b
Pre-stage model -prep-modelOAI_PREP_MODEL → inherit Chat model
Image model -image-modelOAI_IMAGE_MODEL → default gpt-image-1
Chat temperature vs top-p One‐knob rule: if -top-p is set, omit temperature; otherwise send -temp (default 1.0) when supported
Pre-stage temperature vs top-p One‐knob rule applies independently with -prep-temp/-prep-top-p

HTTP controls:

Setting Resolution order
Chat HTTP timeout -http-timeoutOAI_HTTP_TIMEOUT → fallback to -timeout if set
Pre-stage HTTP timeout -prep-http-timeoutOAI_PREP_HTTP_TIMEOUT → inherit Chat HTTP timeout
Image HTTP timeout -image-http-timeoutOAI_IMAGE_HTTP_TIMEOUT → inherit Chat HTTP timeout
Chat HTTP retries -http-retriesOAI_HTTP_RETRIES → default (e.g., 2)
Pre-stage HTTP retries -prep-http-retriesOAI_PREP_HTTP_RETRIES → inherit Chat HTTP retries
Image HTTP retries -image-http-retriesOAI_IMAGE_HTTP_RETRIES → inherit Chat HTTP retries
Chat HTTP retry backoff -http-retry-backoffOAI_HTTP_RETRY_BACKOFF → default
Pre-stage HTTP retry backoff -prep-http-retry-backoffOAI_PREP_HTTP_RETRY_BACKOFF → inherit Chat backoff
Image HTTP retry backoff -image-http-retry-backoffOAI_IMAGE_HTTP_RETRY_BACKOFF → inherit Chat backoff

Quick start

Install the CLI and point it to a reachable OpenAI‐compatible API (local or hosted):

export OAI_BASE_URL=http://localhost:1234/v1
export OAI_MODEL=oss-gpt-20b
make build build-tools # skip if installed via go install / release binary

Create a minimal tools.json next to the binary (Unix/macOS):

{
 "tools": [
 {
 "name": "get_time",
 "description": "Return current time for an IANA timezone (default UTC). Accepts 'timezone' (canonical) and alias 'tz'.",
 "schema": {
 "type": "object",
 "properties": {
 "timezone": {"type": "string", "description": "e.g. Europe/Helsinki"},
 "tz": {"type": "string", "description": "Alias for timezone (deprecated)"}
 },
 "required": ["timezone"],
 "additionalProperties": false
 },
 "command": ["./tools/bin/get_time"],
 "timeoutSec": 5
 }
 ]
}

On Windows, use a .exe suffix for tool binaries:

{
 "tools": [
 {
 "name": "get_time",
 "schema": {"type":"object","properties":{"timezone":{"type":"string"}},"required":["timezone"],"additionalProperties":false},
 "command": ["./tools/bin/get_time.exe"],
 "timeoutSec": 5
 }
 ]
}

Run the agent:

./bin/agentcli \
 -prompt "What's the local time in Helsinki? If tools are available, call get_time." \
 -tools ./tools.json \
 -debug

Expected behavior: the model may call get_time; the CLI executes ./tools/bin/get_time (or get_time.exe on Windows) with JSON on stdin, appends the result as a tool message, calls the API again, then prints a concise final answer.

Tip: run ./bin/agentcli -h for the complete help output.

Usage

Flags are order‐insensitive. You can place -prompt and other flags in any order; precedence remains flag > environment > default.

Common flags

-prompt string User prompt (required)
-tools string Path to tools.json (optional)
-system string System prompt (default: helpful and precise)
-base-url string OpenAI‐compatible base URL (env OAI_BASE_URL; scripts accept LLM_BASE_URL fallback)
-api-key string API key if required (env OAI_API_KEY; falls back to OPENAI_API_KEY)
-model string Model ID (env OAI_MODEL; scripts accept LLM_MODEL fallback)
-max-steps int Maximum reasoning/tool steps (default 8)
 A hard ceiling of 15 is enforced; exceeding the cap
 terminates with: "needs human review".
-http-timeout duration HTTP timeout for chat completions (env OAI_HTTP_TIMEOUT; default falls back to -timeout)
-prep-http-timeout duration HTTP timeout for pre-stage (env OAI_PREP_HTTP_TIMEOUT; default falls back to -http-timeout)
-prep-model string Pre-stage model ID (env OAI_PREP_MODEL; inherits -model if unset)
-prep-base-url string Pre-stage base URL (env OAI_PREP_BASE_URL; inherits -base-url if unset)
-prep-api-key string Pre-stage API key (env OAI_PREP_API_KEY; falls back to OAI_API_KEY/OPENAI_API_KEY; inherits -api-key if unset)
-prep-http-retries int Pre-stage HTTP retries (env OAI_PREP_HTTP_RETRIES; inherits -http-retries if unset)
-prep-http-retry-backoff duration Pre-stage HTTP retry backoff (env OAI_PREP_HTTP_RETRY_BACKOFF; inherits -http-retry-backoff if unset)
-prep-dry-run Run pre-stage only, print refined Harmony messages to stdout, and exit 0
-print-messages Pretty-print the final merged message array to stderr before the main call
-http-retries int Number of retries for transient HTTP failures (timeouts, 429, 5xx). Uses jittered exponential backoff. (default 2)
-http-retry-backoff duration Base backoff between HTTP retry attempts (exponential with jitter). (default 300ms)
-tool-timeout duration Per-tool timeout (default falls back to -timeout)
-timeout duration [DEPRECATED] Global timeout; prefer -http-timeout and -tool-timeout
-temp float Sampling temperature (default 1.0)
-top-p float Nucleus sampling probability mass (conflicts with -temp; omits temperature when set)
-prep-top-p float Nucleus sampling probability mass for pre-stage (conflicts with -temp; omits temperature when set)
-prep-profile string Pre-stage prompt profile (deterministic|general|creative|reasoning); sets temperature when supported (conflicts with -prep-top-p)
-prep-enabled Enable pre-stage (default true). When false, skip pre-stage and proceed directly to main call.
-debug Dump request/response JSON to stderr
-verbose Also print non-final assistant channels (critic/confidence) to stderr
-channel-route name=stdout|stderr|omit
 Override default channel routing (final→stdout, critic/confidence→stderr); repeatable
-quiet Suppress non-final output; print only final text to stdout
-capabilities Print enabled tools and exit
-print-config Print resolved config and exit
-dry-run Print intended state actions (restore/refine/save) and exit without writing state
--version | -version Print version and exit

Run ./bin/agentcli -h to see the built‐in help.

Image generation flags

The following flags control the Images API behavior used by the assistant when generating images. Precedence is always: flags > environment > inheritance > default.

Flag Environment Default / Inheritance Description
-image-base-url string OAI_IMAGE_BASE_URL Inherits -base-url Image API base URL
-image-api-key string OAI_IMAGE_API_KEY Inherits -api-key; falls back to OPENAI_API_KEY API key for Images API
-image-model string OAI_IMAGE_MODEL gpt-image-1 Images model ID
-image-http-timeout duration OAI_IMAGE_HTTP_TIMEOUT Inherits -http-timeout HTTP timeout for image requests
-image-http-retries int OAI_IMAGE_HTTP_RETRIES Inherits -http-retries Retry attempts for transient image HTTP errors
-image-http-retry-backoff duration OAI_IMAGE_HTTP_RETRY_BACKOFF Inherits -http-retry-backoff Base backoff for image HTTP retries
-image-n int OAI_IMAGE_N 1 Number of images to generate
-image-size string OAI_IMAGE_SIZE 1024x1024 Size WxH
-image-quality string OAI_IMAGE_QUALITY standard standard or hd
-image-style string OAI_IMAGE_STYLE natural natural or vivid
-image-response-format string OAI_IMAGE_RESPONSE_FORMAT url url or b64_json
-image-transparent-background OAI_IMAGE_TRANSPARENT_BACKGROUND false Request transparent background when supported

Why you usually don’t need to change knobs

  • The default -temp 1.0 is standardized for broad provider/model parity and GPT‐5 compatibility.
  • The one‐knob rule applies: if you set -top-p, the agent omits temperature; otherwise it sends temperature (default 1.0) and leaves top_p unset.
  • The one‐knob rule applies for both stages: if you set -top-p (or -prep-top-p), the agent omits temperature for that stage; otherwise it sends temperature (default 1.0) when supported. Pre‐stage profiles are available via -prep-profile, e.g. deterministic sets temperature to 0.1 when supported.
  • See the policy for details and rationale: ADR‐0004: Default LLM policy.

Capabilities

List enabled tools from a manifest without running the agent. The output includes a prominent header warning, and certain tools like img_create are annotated with an extra warning because they make outbound network calls and can save files:

./bin/agentcli -tools ./tools.json -capabilities

Examples

Zero-config with GPT-5

Run against a GPT‐5 compatible endpoint without tuning sampling knobs. The CLI sends temperature: 1.0 by default for models that support it.

./bin/agentcli -prompt "Say ok" -model gpt-5 -base-url "$OAI_BASE_URL" -api-key "$OAI_API_KEY" -max-steps 1 -debug
# stderr will include a request dump containing "\"temperature\": 1"

Tool calls transcript

Minimal JSON transcript showing correct tool‐call sequencing:

[
 {"role":"user","content":"What's the local time in Helsinki?"},
 {
 "role":"assistant",
 "content":null,
 "tool_calls":[
 {
 "id":"call_get_time_1",
 "type":"function",
 "function":{
 "name":"get_time",
 "arguments":"{\"timezone\":\"Europe/Helsinki\"}"
 }
 }
 ]
 },
 {
 "role":"tool",
 "tool_call_id":"call_get_time_1",
 "name":"get_time",
 "content":"{\"timezone\":\"Europe/Helsinki\",\"iso\":\"2025年08月17日T12:34:56Z\",\"unix\":1755424496}"
 },
 {"role":"assistant","content":"It's 15:34 in Helsinki."}
]

Notes:

  • For parallel tool calls (multiple entries in tool_calls), append one role:"tool" message per id before calling the API again. Order of tool messages is not significant as long as each tool_call_id is present exactly once.
  • Transcript hygiene: when running without -debug, the CLI replaces any single tool message content larger than 8 KiB with {"truncated":true,"reason":"large-tool-output"} before sending to the API. Use -debug to inspect full payloads during troubleshooting.

Worked example: tool calls and transcript

See examples/tool_calls.md for a self-contained, test-driven worked example that:

  • Exercises default temperature 1.0
  • Demonstrates a two-tool-call interaction with matching tool_call_id
  • Captures a transcript via -debug showing request/response JSON dumps

Run the example test:

go test ./examples -run TestWorkedExample_ToolCalls_TemperatureOne_Sequencing -v

Split backends for chat and image

Use one provider for chat and another for image generation by overriding the image backend only:

export OAI_BASE_URL=https://api.example-chat.local/v1
export OAI_API_KEY=chat-key
./bin/agentcli \
 -prompt "Create a simple logo" \
 -tools ./tools.json \
 -image-base-url https://api.openai.com/v1 \
 -image-api-key "$OPENAI_API_KEY" \
 -image-model gpt-image-1 \
 -image-size 1024x1024

View refined messages (pre-stage and final)

See also ADR‐0005 for the pre‐stage flow and channel routing details: docs/adr/0005-harmony-pre-processing-and-channel-aware-output.md. Inspect message arrays deterministically without running the full loop:

# Pre-stage only: print refined Harmony messages and exit
./bin/agentcli -prompt "Say ok" -prep-dry-run | jq .
# Before the main call: pretty-print merged messages to stderr, then proceed
./bin/agentcli -prompt "Say ok" -print-messages 2> >(jq .)

Exec tool

Build the exec tool and run a simple command (Unix):

make build-tools
echo '{"cmd":"/bin/echo","args":["hello"]}' | ./tools/bin/exec
# => {"exitCode":0,"stdout":"hello\n","stderr":"","durationMs":<n>}

Timeout example:

echo '{"cmd":"/bin/sleep","args":["2"],"timeoutSec":1}' | ./tools/bin/exec
# => non-zero exit, stderr contains "timeout"

Filesystem tools

The following examples assume make build-tools has produced binaries into tools/bin/*.

fs_read_file

make build-tools
printf 'hello world' > tmp_readme_demo.txt
echo '{"path":"tmp_readme_demo.txt"}' | ./tools/bin/fs_read_file | jq .
rm -f tmp_readme_demo.txt

fs_append_file

make build-tools
echo -n 'hello ' | base64 > b64a.txt
echo -n 'world' | base64 > b64b.txt
echo '{"path":"tmp_append_demo.txt","contentBase64":"'"$(cat b64a.txt)"'"}' | ./tools/bin/fs_append_file | jq .
echo '{"path":"tmp_append_demo.txt","contentBase64":"'"$(cat b64b.txt)"'"}' | ./tools/bin/fs_append_file | jq .
cat tmp_append_demo.txt; rm -f tmp_append_demo.txt b64a.txt b64b.txt

fs_write_file

make build-tools
echo -n 'hello world' | base64 > b64.txt
echo '{"path":"tmp_write_demo.txt","contentBase64":"'"$(cat b64.txt)"'"}' | ./tools/bin/fs_write_file | jq .
cat tmp_write_demo.txt; rm -f tmp_write_demo.txt b64.txt

fs_mkdirp

make build-tools
echo '{"path":"tmp_mkdirp_demo/a/b/c","modeOctal":"0755"}' | ./tools/bin/fs_mkdirp | jq .
ls -ld tmp_mkdirp_demo/a/b/c
echo '{"path":"tmp_mkdirp_demo/a/b/c","modeOctal":"0755"}' | ./tools/bin/fs_mkdirp | jq .
rm -rf tmp_mkdirp_demo

fs_rm

make build-tools
printf 'temp' > tmp_rm_demo.txt
echo '{"path":"tmp_rm_demo.txt"}' | ./tools/bin/fs_rm | jq .
mkdir -p tmp_rm_dir/a/b && touch tmp_rm_dir/a/b/file.txt
echo '{"path":"tmp_rm_dir","recursive":true}' | ./tools/bin/fs_rm | jq .
rm -rf tmp_rm_dir

fs_move

make build-tools
printf 'payload' > tmp_move_src.txt
echo '{"from":"tmp_move_src.txt","to":"tmp_move_dst.txt"}' | ./tools/bin/fs_move | jq .
printf 'old' > tmp_move_dst.txt; printf 'new' > tmp_move_src.txt
echo '{"from":"tmp_move_src.txt","to":"tmp_move_dst.txt","overwrite":true}' | ./tools/bin/fs_move | jq .
rm -f tmp_move_src.txt tmp_move_dst.txt

fs_listdir

make build-tools
mkdir -p tmp_listdir_demo/a b && touch tmp_listdir_demo/.hidden tmp_listdir_demo/a/afile tmp_listdir_demo/bfile
echo '{"path":"tmp_listdir_demo"}' | ./tools/bin/fs_listdir | jq '.entries | map(.path)'
jq -n '{path:"tmp_listdir_demo",recursive:true,globs:["**/*"],includeHidden:false}' | ./tools/bin/fs_listdir | jq '.entries | map(select(.type=="file") | .path)'
rm -rf tmp_listdir_demo

fs_apply_patch

make build-tools
cat > /tmp/demo.diff <<'EOF'
--- /dev/null
+++ b/tmp_patch_demo.txt
@@ -0,0 +1,2 @@
+hello
+world
EOF
jq -n --arg d "$(cat /tmp/demo.diff)" '{unifiedDiff:$d}' | ./tools/bin/fs_apply_patch | jq .
printf 'hello
world
' | diff -u - tmp_patch_demo.txt && echo OK

fs_edit_range

make build-tools
printf 'abcdef' > tmp_edit_demo.txt
echo -n 'XY' | base64 > b64.txt
jq -n --arg b "$(cat b64.txt)" '{path:"tmp_edit_demo.txt",startByte:2,endByte:4,replacementBase64:$b}' | ./tools/bin/fs_edit_range | jq .
cat tmp_edit_demo.txt # => abXYef
rm -f tmp_edit_demo.txt b64.txt

fs_stat

make build-tools
printf 'hello world' > tmp_stat_demo.txt
echo '{"path":"tmp_stat_demo.txt","hash":"sha256"}' | ./tools/bin/fs_stat | jq .
rm -f tmp_stat_demo.txt

Image generation tool (img_create)

Generate images via an OpenAI‐compatible Images API and save files into your repository (default) or return base64 on demand.

Quickstart (Unix/macOS/Windows via make build-tools):

make build-tools

Minimal tools.json entry (copy/paste next to your binary):

{
 "tools": [
 {
 "name": "img_create",
 "description": "Generate image(s) with OpenAI Images API and save to repo or return base64",
 "schema": {
 "type": "object",
 "required": ["prompt"],
 "properties": {
 "prompt": {"type": "string"},
 "n": {"type": "integer", "minimum": 1, "maximum": 4, "default": 1},
 "size": {"type": "string", "pattern": "^\\d{3,4}x\\d{3,4}$", "default": "1024x1024"},
 "model": {"type": "string", "default": "gpt-image-1"},
 "return_b64": {"type": "boolean", "default": false},
 "save": {
 "type": "object",
 "required": ["dir"],
 "properties": {
 "dir": {"type": "string"},
 "basename": {"type": "string", "default": "img"},
 "ext": {"type": "string", "enum": ["png"], "default": "png"}
 },
 "additionalProperties": false
 }
 },
 "additionalProperties": false
 },
 "command": ["./tools/bin/img_create"],
 "timeoutSec": 120,
 "envPassthrough": ["OAI_API_KEY", "OAI_BASE_URL", "OAI_IMAGE_BASE_URL", "OAI_HTTP_TIMEOUT"]
 }
 ]
}

Run the agent with a prompt that instructs the assistant to call img_create and save under assets/:

export OAI_BASE_URL=${OAI_BASE_URL:-https://api.openai.com/v1}
export OAI_API_KEY=your-key
./bin/agentcli \
 -tools ./tools.json \
 -prompt "Generate a tiny illustrative image using img_create and save it under assets/ with basename banner" \
 -debug
# Expect: one or more PNGs under assets/ (e.g., assets/banner_001.png) and a concise final message on stdout

Notes:

  • By default, the tool writes image files and does not include base64 in transcripts, avoiding large payloads.
  • To return base64 instead, pass { "return_b64": true } to the tool; base64 is elided in stdout unless IMG_CREATE_DEBUG_B64=1 or DEBUG_B64=1 is set.
  • Windows: the built binary is ./tools/bin/img_create.exe and tools.json should reference the .exe.
  • See Troubleshooting for network/API issues and timeouts: docs/runbooks/troubleshooting.md.

fs_search

make build-tools
mkdir -p tmp_search_demo && printf 'alpha\nbeta\ngamma\n' > tmp_search_demo/sample.txt
jq -n '{query:"^ga",globs:["**/*.txt"],regex:true}' | ./tools/bin/fs_search | jq '.matches'
rm -rf tmp_search_demo

Security

  • Tools are an explicit allowlist from tools.json
  • No shell interpretation; commands executed via argv only
  • JSON contract on stdin/stdout; strict timeouts per call
  • Treat model output as untrusted input; never pass it to a shell

See the full threat model in docs/security/threat-model.md.

Unrestricted tools warning

  • Enabling exec grants arbitrary command execution and may allow full network access. Treat this as remote code execution.
  • Run the CLI and tools in a sandboxed environment (container/jail/VM) with least privilege.
  • Keep tools.json minimal and audited. Do not pass secrets via tool arguments; prefer environment variables or CI secret stores.
  • Audit log redaction: set GOAGENT_REDACT to mask sensitive values in audit entries. OAI_API_KEY/OPENAI_API_KEY are always masked if present.

State persistence (-state-dir)

Persist and restore execution state to make repeated runs deterministic and faster.

  • Enable by passing -state-dir <dir> (or AGENTCLI_STATE_DIR). The directory must be private (0700).
  • On first run, the CLI saves a snapshot state-<RFC3339UTC>-<8charSHA>.json and a pointer file latest.json.
  • On subsequent runs with the same scope, the CLI restores prompts/settings and skips pre-stage unless -state-refine is provided.
  • Partition contexts with -state-scope (or AGENTCLI_STATE_SCOPE); when unset, a default scope is derived from model, base URL, and toolset.
  • Inspect actions without touching disk using -dry-run.

Examples:

# First run saves a snapshot
./bin/agentcli -prompt "Say ok" -tools ./tools.json -state-dir "$PWD/.agent-state"
# Restore and skip pre-stage
./bin/agentcli -prompt "Say ok" -tools ./tools.json -state-dir "$PWD/.agent-state"
# Refine existing state with inline text
./bin/agentcli -prompt "Say ok" -state-dir "$PWD/.agent-state" -state-refine -state-refine-text "Tighten tone"
# Use a custom scope to keep contexts separate
./bin/agentcli -prompt "Say ok" -state-dir "$PWD/.agent-state" -state-scope docs-demo

See ADR‐0012 for rationale and details: docs/adr/0012-state-dir-persistence.md.

Troubleshooting

Common issues and deterministic fixes are documented with copy‐paste commands in docs/runbooks/troubleshooting.md.

Documentation

Start with the Documentation index for design docs, ADRs, and references:

Diagrams

  • Agent loop: docs/diagrams/agentcli-seq.md
  • Toolbelt interactions: docs/diagrams/toolbelt-seq.md
  • Pre‐stage flow: docs/diagrams/harmony-prep-seq.md

Tests

Run the full test suite (offline):

go test ./...

Lint, vet, and formatting checks:

make lint
make fmt # apply gofmt -s -w to the repo

Guarded logs cleanup:

# Only removes ./logs when ./logs/STATE trimmed equals DOWN
make clean-logs
# End-to-end verification of the guard logic (creates temp dirs)
make test-clean-logs

Reproducible builds: the Makefile uses -trimpath and stripped -ldflags with VCS stamping disabled so two clean builds produce identical binaries. Verify locally by running two consecutive make clean build build-tools and comparing sha256sum outputs.

Contributing

Contributions are welcome! See CONTRIBUTING.md for workflow, coding standards, and how to run quality gates locally. Please also read CODE_OF_CONDUCT.md.

Useful local helpers during development:

  • make check-tools-paths — enforce canonical tools/cmd/NAME sources and tools/bin/NAME invocations (requires rg)
  • make verify-manifest-paths — ensure relative tools.json commands use ./tools/bin/NAME (absolute allowed in tests)
  • make build-tool NAME=<name> — build a single tool binary into tools/bin/NAME
  • make check-go-version — fail fast if your local Go major.minor differs from go.mod

If your local toolchain does not match, you will see:

Go toolchain mismatch: system X.Y != go.mod X.Y

Remediation: install the matching Go version shown by go.mod (e.g., from the official downloads) or switch via your version manager, then rerun make check-go-version.

Tooling

This repository pins the toolchain for deterministic results:

  • CI uses the Go version declared in go.mod across all OS jobs.
  • Linting is performed with a pinned golangci-lint version managed by the Makefile.

See ADR‐0003 for the full policy and rationale: docs/adr/0003-toolchain-and-lint-policy.md.

Support

  • Open an issue on the tracker: Issues
    • For security concerns, avoid posting secrets in logs. If a private report is needed, open an issue with minimal detail and a maintainer will reach out.
  • Follow updates from the author on LinkedIn: Jaakko Heusala

Roadmap

Planned improvements and open ideas are tracked in FUTURE_CHECKLIST.md. Larger architectural decisions are recorded under docs/adr/ (see ADR‐0001 and ADR‐0002). Contributions to the roadmap are welcome via issues and PRs.

Project status

Experimental, but actively maintained. Interfaces may change before a stable 1.0.

License and credits

MIT license. See LICENSE.

Maintainers and authors:

  • Hyperify.io maintainers
  • Primary author: Jaakko Heusala

Acknowledgements: inspired by OpenAI‐compatible agent patterns; built for portability and safety.

Changelog

See CHANGELOG.md for notable changes and release notes.

More examples

See examples/unrestricted.md for copy‐paste prompts demonstrating exec + file tools to write, build, and run code in a sandboxed environment.

About

Autonomous AI agent

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Contributors 3

AltStyle によって変換されたページ (->オリジナル) /