cjules

Version, currently 0.2.24 versions

github.com/hahwul/cjules

A power-user CLI for the Jules API in Crystal. Multi-account auth, bulk ops, watch mode, gitPatch extraction, markdown activity export, and pipe-friendly outputs.

6 stars
0 dependents
License: MIT

Installation

# Add this to your shard.yml
dependencies:
  cjules:
    github: hahwul/cjules
    version: ~> 0.2.2

Then run:

shards install

shard.yml

Crystal
>= 1.20.0
License
MIT
Author
hahwul <hahwul@gmail.com>
Target
  • cjules from src/main.cr

Dependencies

Development Dependencies

  • ameba~> 1.6github: crystal-ameba/amebadev
  • webmock~> 0.14github: manastech/webmock.crdev

README

<div align="center">
  <img alt="cjules Logo" src="logo.webp" width="120px;">
  <p>A power-user CLI for the Jules API, written in Crystal.</p>
</div>

<p align="center">
<a href="https://github.com/hahwul/cjules/blob/main/CONTRIBUTING.md">
<img src="https://img.shields.io/badge/CONTRIBUTIONS-WELCOME-000000?style=for-the-badge&labelColor=black"></a>
<a href="https://github.com/hahwul/cjules/releases">
<img src="https://img.shields.io/github/v/release/hahwul/cjules?style=for-the-badge&color=black&labelColor=black&logo=web"></a>
<a href="https://crystal-lang.org">
<img src="https://img.shields.io/badge/Crystal-000000?style=for-the-badge&logo=crystal&logoColor=white"></a>
</p>

A scriptable CLI for [Jules](https://jules.google), written in Crystal.

- **Git-aware `new`** — auto-detects `--repo` and `--branch`; reads the prompt from args, `stdin`, or `--file`.
- **Parallel sessions** — `cjules new --parallel N` runs N sessions with the same prompt.
- **Watch** — `cjules watch <id>` tails activities; `--auto-approve --reply` for hands-free runs.
- **Prune** — filter by state, age, repo, or `--all`; dry-run by default, `-y` to apply.
- **Patch & PR** — `cjules patch <id> --apply` (or `-i` for interactive hunks) runs `git apply`; `cjules pr <id> --open` opens the PR.
- **Logs** — `cjules logs <id> -f md` for a full report, `--bash` for shell transcripts, `--save-media` for artifacts.
- **Pipe-friendly** — `-f table|json|jsonl|yaml` on every list command.
- **Multi-account** — aliases via `cjules accounts use`, or one-shot with `--account`.
- **Pick** — `cjules pick` (uses `fzf` if available) with `--action show|watch|pr|delete`.
- **Retry** — `cjules retry <id>` re-runs a session by cloning its prompt, repo, branch, and flags; `--with-failure-reason` carries the original failure message into the new prompt.
- **Templates** — drop reusable prompts into `~/.config/cjules/templates/` and reference them via `--template <name>` on `new` or `retry`. Templates support dynamic variables: `{{.File "path"}}`, `{{.GitDiff}}`, and `{{.Var "name"}}` for powerful prompt generation.

> **Heads up:** the Jules API is currently labelled `v1alpha`. Schema and
> behaviour can change without notice. Pin a release of cjules in scripts you
> care about and read the [CHANGELOG](CHANGELOG.md) when upgrading.

## Install
### Homebrew
```
brew tap hahwul/cjules
brew install cjules
```

### Build from Source
```sh
shards build --release
install bin/cjules /usr/local/bin/
```

### AI Skill

```sh
npx skills add hahwul/cjules
```

## Auth

Issue an API key at [jules.google.com/settings/api](https://jules.google.com/settings/api) and save it with `cjules login`.

```sh
cjules login --alias work        # prompts for the API key (input hidden)
cjules login --alias personal --key AIza...
cjules accounts ls
cjules accounts use personal
cjules logout work
```

Resolution order: `JULES_API_KEY` env var → `JULES_ACCOUNT` env var → active alias from config.

## Examples

### Creating sessions

```sh
# Create a session for the current git repo/branch
cjules new "Add a healthcheck endpoint"

# Pipe a longer prompt and let Jules open the PR automatically
cat PROMPT.md | cjules new --auto-pr -

# Read the prompt from a file, override repo/branch, require plan approval
cjules new --file PROMPT.md --repo hahwul/cjules --branch main --require-approval

# Repoless session (no sourceContext)
cjules new --no-repo "Draft release notes for v0.2.0"

# Fan out N parallel sessions with the same prompt and capture the IDs
cjules new --parallel 5 --auto-pr "Refactor the config loader" -f json | jq -r '.[].id' > ids.txt
```

> **Burst submissions:** under heavy parallelism the Jules API can return
> `HTTP 400 Precondition check failed` for a session that did get created
> server-side. By default `cjules new` reconciles 4xx failures by matching
> against sessions in the account that were created since the call started
> (preferring `--title`, falling back to the prompt). Pass
> `--no-reconcile-on-error` to opt out and surface the raw error.

### Watching and steering

```sh
# Watch a session live (3s default poll)
cjules watch <session-id> --interval 5

# Hands-free run: auto-approve plans and reply to feedback prompts
cjules watch <session-id> --auto-approve --reply

# Send a follow-up message
cjules msg <session-id> "Also add a /readyz endpoint"

# Or pipe one in
echo "Please add tests for the error path" | cjules msg <session-id> -

# Approve a pending plan explicitly
cjules approve <session-id>
```

### Listing, filtering, piping

```sh
# Recent failures as JSONL, pipe into jq
cjules ls --state FAILED --since 7d -f jsonl | jq -r '.id + "\t" + .title'

# Re-pull logs for the latest failure
cjules ls --state FAILED --since 7d -f jsonl | jq -r .id | head -1 | xargs cjules logs

# Interactive picker (uses fzf if installed) — default action shows the session
cjules pick
cjules pick --action watch        # pick → watch
cjules pick --action pr           # pick → print PR URL
```

### Patches, PRs, exports

```sh
# Inspect or apply the resulting patch locally
cjules patch <session-id> --list
cjules patch <session-id> --apply
cjules patch <session-id> --interactive  # select hunks (like `git add -p`)

# Print or open the PR
cjules pr <session-id>
cjules pr <session-id> --open

# Full session report as Markdown
cjules logs <session-id> -f md > report.md

# Pull only bash command/output blocks (handy for debugging long runs)
cjules logs <session-id> --bash

# Save media artifacts (screenshots, etc.) to a directory
cjules logs <session-id> --save-media ./artifacts
```

### Re-running with `retry`

`retry` clones a session's prompt, repo, branch, title, and `--auto-pr` /
`--require-approval` flags into a brand-new session. Handy for FAILED runs.

```sh
# Plain retry: same prompt, same repo/branch, new session
cjules retry <session-id>

# Retry and feed the original failure reason back into the prompt
cjules retry <session-id> --with-failure-reason

# Tweak the prompt for the next attempt without losing the rest of the context
cjules retry <session-id> --note "Skip the migration step this time."

# Override prompt or branch entirely
cjules retry <session-id> --prompt "New approach: ..."
cjules retry <session-id> --branch experimental-fix

# Pick the most-recent failure and retry it in one line
cjules ls --state FAILED --limit 1 -f jsonl | jq -r .id | xargs cjules retry --with-failure-reason
```

### Reusable prompts with `templates`

Drop `*.md` or `*.txt` files into `~/.config/cjules/templates/` and reference
them by filename. Templates are looked up there by short name.

Templates now support **dynamic variables** for powerful prompt generation:
- `{{.File "path"}}` — Insert file contents
- `{{.GitDiff}}` — Insert current git diff
- `{{.Var "name"}}` — Insert user-defined variables passed via `--var`

```sh
# See what's available and where they live
cjules templates ls
cjules templates path
cjules templates show bugfix       # print body

# Use a template as the prompt for a new session
cjules new --template bugfix
cjules new --template bugfix --auto-pr --branch hotfix

# Use templates with variables
cjules new --template refactor --var file=parser.cr --var priority=high

# Or as the prompt for a retry
cjules retry <session-id> --template bugfix
```

**Example template** (`~/.config/cjules/templates/refactor.md`):
```markdown
Please refactor the following code:

[Code]
{{.File "src/parser.cr"}}

[Notes]
{{.Var "note"}}

[Current Changes]
{{.GitDiff}}
```

**Usage:**
```sh
cjules new --template refactor --var note="Improve error handling"
```

### Bulk cleanup with `prune`

`prune` is dry-run by default — review the matches, then re-run with `-y` to actually delete.

```sh
# Preview what would be deleted
cjules prune --completed --older-than 30d

# Actually delete after the preview looks right
cjules prune --completed --older-than 30d -y

# Sweep failed sessions for a specific repo
cjules prune --failed --repo hahwul/cjules -y

# Match an arbitrary state
cjules prune --state AWAITING_USER_FEEDBACK --older-than 14d -y

# Wipe every session for the active account (cannot be combined with other filters)
cjules prune --all          # dry-run preview
cjules prune --all -y       # prompts for typed 'yes' confirmation

# One-off targeted delete (no filters needed)
cjules rm <session-id> <session-id> ...
```

### Multi-account workflows

```sh
# Run a single command against a non-active account
cjules --account personal ls --since 24h

# One-off override via env var
JULES_ACCOUNT=work cjules new "Bump dependencies"
JULES_API_KEY=AIza... cjules ls
```

## Config

Stored at `~/.config/cjules/config.yml` with `0600` permissions. Set defaults:

```sh
cjules config set default_repo  hahwul/cjules
cjules config set default_branch main
```

## Shell completion

```sh
cjules completion zsh   > "${fpath[1]}/_cjules"
cjules completion bash  > /etc/bash_completion.d/cjules
cjules completion fish  > ~/.config/fish/completions/cjules.fish
```

## Development

```sh
shards build
crystal spec
just lint      # requires shards install (pulls ameba)
just check     # format check
```

## License

MIT — see `LICENSE`.