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.

7 stars
0 dependents
License: MIT

Installation

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

Then run:

shards install

shard.yml

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

Dependencies

Development Dependencies

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

README

[!WARNING] Jules is shutting down, so cjules is no longer maintained. Google announced that Jules becomes read-only after November 11, 2026 and shuts down on December 31, 2026. v0.3.0 is the final release of cjules. The repository will be archived after that. Your code, branches, and PRs stay on GitHub. To keep session history, use the official export from the announcement before the service goes away.

A scriptable CLI for Jules, 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 --notify desktop|slack|discord 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.
  • Git helpers — cjules commit-msg generates a commit message from git diff (or a session); cjules pr-describe <id> --copy generates a Markdown PR description from the session's actions and patch.
  • 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; cjules troubleshoot <id> diagnoses compile errors, missing shards, and failing specs from the logs and offers a retry with a fix note.
  • 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 when upgrading.

Install

Homebrew

brew tap hahwul/cjules
brew install cjules

Build from Source

shards build --release
install bin/cjules /usr/local/bin/

AI Skill

npx skills add hahwul/cjules

Auth

Issue an API key at jules.google.com/settings/api and save it with cjules login.

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

# 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

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

# Hands-free run: auto-approve plans, reply to feedback prompts, and send desktop/webhook notifications
cjules watch <session-id> --auto-approve --reply --notify desktop
cjules watch <session-id> --notify slack,discord

# 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

# 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

# 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

# Generate a Markdown PR description (and optionally copy to clipboard)
cjules pr-describe <session-id>
cjules pr-describe <session-id> --copy

# Generate a commit message from local git diff or from a session's patch
cjules commit-msg
cjules commit-msg --staged --copy
cjules commit-msg <session-id> --copy

# 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.

# 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

# Diagnose a failure from its bash logs and retry with a suggested fix note
cjules troubleshoot <session-id>          # asks [Y/n] before retrying
cjules troubleshoot <session-id> --dry-run
cjules troubleshoot <session-id> --yes

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
# 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):

Please refactor the following code:

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

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

[Current Changes]
{{.GitDiff}}

Usage:

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.

# 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

# 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:

cjules config set default_repo    hahwul/cjules
cjules config set default_branch  main
cjules config set slack_webhook   https://hooks.slack.com/services/...
cjules config set discord_webhook https://discord.com/api/webhooks/...

Shell completion

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

Development

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

License

MIT — see LICENSE.