Skip to content

dottorblaster/amake

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

19 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

amake

A task runner for AI CLI tools. Think make, but for dispatching prompts to things like Claude Code, Aider, GitHub Copilot, etc.

You define tasks in a TOML file, each with a prompt and a tool. amake run <task> figures out the right CLI invocation and runs it. Tasks can depend on each other, pass captured output downstream, and optionally run inside a clampdown sandbox.

Install

cargo install --path .

You'll need Rust 2024 edition (1.85+).

Quick start

Create an Amakefile in your project root:

[defaults]
tool = "claude-code"

[tasks.create-pr]
prompt = """
Create a PR for the current branch.
Write a clear description based on the diff.
"""
auto_approve = true

[tasks.review]
depends = ["create-pr"]
prompt = "Review the changes in the current branch. Be concise."

Then:

amake run review

This runs create-pr first (because review depends on it), then review. Both use claude-code since that's the default.

Amakefile format

The config file can be called Amakefile or amake.toml. amake searches upward from the current directory to find it, same as make does.

Defaults

[defaults]
tool = "claude-code"    # used when a task doesn't specify its own
workdir = "./src"       # optional, sets cwd for all tasks

Tasks

[tasks.refactor]
tool = "aider"                          # override the default tool
prompt = "Refactor error handling to use thiserror."
files = ["src/main.rs", "src/error.rs"] # context files passed to the tool
auto_approve = true                     # tool-specific "don't ask" flag
extra_args = ["--model", "gpt-4"]       # passed verbatim to the tool CLI
timeout = 300                           # seconds; kill the child if it runs longer (optional)

Timeout and retry

AI CLIs hang and flake. timeout (in seconds) caps how long a single attempt may run; [tasks.<name>.retry] re-runs failed attempts with backoff:

[tasks.review]
prompt = "Review the diff."
timeout = 300

[tasks.review.retry]
attempts = 3                # total runs (default 1, i.e. no retry)
backoff = "exponential"     # "fixed" | "linear" | "exponential" (default)
initial_delay = 1           # seconds (default 1)
max_delay = 30              # cap for linear/exponential (default 30)
on_timeout = true           # also retry when the timeout fires (default true)

Both timeout and retry can also be set under [defaults] to apply to every task; per-task values override.

A task can depend on other tasks and use their captured output:

[tasks.describe]
prompt = "Describe what this repo does in one paragraph."
capture = true

[tasks.review]
depends = ["describe"]
prompt = """
Here's a summary of the repo:
{{tasks.describe.stdout}}

Now review the open PR for correctness.
"""

Template variables

Prompts support {{...}} placeholders from three sources:

Syntax Source
{{tasks.foo.stdout}} Captured output from task foo (must be in depends, must have capture = true)
{{vars.name}} Defined in the [vars] table, or passed via --var name=value / --edit-var name on the CLI
{{env.HOME}} Read from the environment

Missing variables are a hard error — no silent empty strings.

Variables in the Amakefile

You can declare vars directly in the Amakefile under a [vars] table:

[vars]
who = "world"
branch = "$(git rev-parse --abbrev-ref HEAD)"
today = "$(date +%Y-%m-%d)"

Values support shell command substitution. Anything inside $(...) is run through sh -c when the Amakefile loads, and its stdout (with the trailing newline trimmed) is inlined into the value. If the command exits non-zero, loading fails with the command's stderr.

Precedence is [vars] < --var < --edit-var. Anything passed on the command line overrides what's in the file.

Editor-based variables

For longer or multiline content, use --edit-var instead of --var. This opens your $VISUAL or $EDITOR (falling back to vi) with a temporary file. Write the value, save, and close — the content becomes the variable's value.

amake run review-pr --edit-var focus

The temporary file starts with comment lines (prefixed #) that are stripped from the final value. If you specify multiple --edit-var flags, each one opens the editor sequentially, one at a time.

If both --var name=value and --edit-var name are given, the editor value wins.

Built-in adapters

$ amake adapters
aider
claude-code
copilot
Adapter Binary Auto-approve Notes
claude-code claude --dangerously-skip-permissions Prompt via --print
aider aider --yes Prompt via --message
copilot gh (none) Runs gh copilot suggest -t shell

If the tool name doesn't match a built-in, amake treats it as a bare binary and passes extra_args + prompt as a positional arg. Good enough for most things:

[tasks.lint]
tool = "openclaw"
prompt = "Fix all clippy warnings."
extra_args = ["--auto-fix"]

Sandbox support

Tasks can run inside clampdown for filesystem/network isolation:

[tasks.untrusted-refactor]
prompt = "Refactor the auth module."
auto_approve = true

[tasks.untrusted-refactor.sandbox]
agent_policy = "deny"
agent_allow = ["api.github.com"]
memory = "4g"
cpus = "4"
tripwire = true
protect = [".env.production"]

This wraps the invocation through clampdown instead of calling the tool directly:

clampdown claude --agent-policy deny --agent-allow api.github.com \
  --memory 4g --cpus 4 --tripwire --protect .env.production \
  --workdir /path/to/project -- --dangerously-skip-permissions --print "Refactor the auth module."

You can set sandbox defaults for all tasks:

[defaults.sandbox]
agent_policy = "deny"
memory = "8g"
gitconfig = true

A task can opt out with sandbox = false.

CLI flags --sandbox and --no-sandbox override everything — useful for testing.

Currently only claude-code is supported by clampdown. Other tools fall back to running without the sandbox (with a warning).

Sandbox options

agent_policy, agent_allow, pod_policy, memory, cpus, protect, mask, unmask, gitconfig, gh, ssh, tripwire, extra_args — these map directly to clampdown flags. See clampdown's docs for details.

CLI reference

amake run <TASKS>... [OPTIONS]

  --dry-run              Print commands without running them
  -k, --keep-going       Don't stop on first failure
  --var <KEY=VALUE>      Set a template variable (repeatable)
  --edit-var <NAME>      Open $EDITOR to input a variable value (repeatable)
  -f, --file <PATH>      Explicit Amakefile path
  --sandbox              Force sandbox for all tasks
  --no-sandbox           Disable sandbox for all tasks

amake list               Show all tasks
amake adapters           Show built-in adapter names

--dry-run still resolves templates, so it's useful for checking that your variables and dependencies are wired up right.

A bigger example

[defaults]
tool = "claude-code"

[defaults.sandbox]
agent_policy = "deny"
agent_allow = ["api.github.com"]
memory = "8g"
gitconfig = true
gh = true

[tasks.create-pr]
prompt = """
Create a PR for the current branch.
Write a clear description based on the diff.
"""
capture = true
auto_approve = true

[tasks.review-pr]
tool = "copilot"
depends = ["create-pr"]
prompt = """
Review the PR:
{{tasks.create-pr.stdout}}

Focus on: {{vars.focus}}
"""

[tasks.refactor]
tool = "aider"
prompt = "Refactor error handling to use thiserror."
files = ["src/main.rs", "src/error.rs"]
auto_approve = true
extra_args = ["--model", "gpt-4"]
amake run review-pr --var focus="security and error handling"

This runs create-pr first, captures its output, then passes it into review-pr's prompt.

About

A task runner for AI CLI tools

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors

Languages