acra-cli
Agentic CLI for LLM-powered research, task execution, code generation, workflow automation, memory, and sandboxed validation.
acra-cli is an installable Python package that provides the acra command-line tool and a reusable LangGraph-based agent workflow. Install the package as acra-cli, run it from the terminal as acra, and import the Python package as acra.
It is built for developers who want a local CLI for asking an LLM-powered agent to research, plan, generate code, validate generated projects, and keep workflow context across runs.
Status: beta. The package is usable, but some CLI command groups are still scaffolds. The most complete surfaces today are installation, provider configuration, profile setup, key management, the interactive shell, research workflows, and Python-level workflow APIs.
Highlights
- Installable PyPI package:
acra-cli - Console command:
acra - Python import package:
acra - Interactive CLI shell powered by Typer, Rich, and prompt-toolkit
- LangGraph workflow with planner, researcher, coder, executor, critic, memory, and human nodes
- Provider support for Gemini, OpenAI, Groq, Ollama, and HuggingFace
- Configuration profiles stored in
~/.acra/config.json - OS keyring support for API keys
- Research command with depth, sources, formatting, output, JSON, and memory options
- Generated project saving and validation
- ChromaDB-backed vector memory and JSON workflow memory modules
- Optional extras for provider-specific dependencies and checkpoint backends
What's New in 0.2.2
acra memory, acra session, acra brain, and acra graph were all previously stub commands that printed placeholder text and did nothing. This release wires them to the backends that already existed, fixes model selection being silently ignored, and fixes two bugs in where generated files actually end up.
New features
acra memory list,search, andclearare now real, scoped to the current directory's project.clearasks for confirmation (--yesto skip it). Newacra memory statsshows success rate and average quality score for the project.acra session listshows every project acra has continuity for, with directory, profile, and a live run count / success rate.acra session resume <id>looks up which directory a thread belongs to.acra brain modelsnow covers all six supported providers (was two).acra brain testactually checks whether the brain's provider has a key configured, instead of an unconditional stub.acra graph showis wired to the real workflow graph: a summary table by default,--mermaidfor the raw diagram source,--save <path>to export it.
Bug fixes
- Model selection was silently ignored.
acra config initsaved a model to your profile, but nothing ever read it -- only environment variables mattered. Provider and model now resolve as env var, then profile, then default, correctly per provider (a profile's model for one provider is never misapplied if an env var switches to a different provider).acra config shownow displays what's actually in effect and where it came from. workspacehad no effect. A profile's saved workspace directory was only ever used for cosmetic display; every generated project always landed under the fixed global data directory regardless of what workspace was configured. Generated projects now save to the configured workspace, falling back to the previous global location when none is set.- Generated files were sometimes never saved at all. For
build,ask,review, andexplain(all of which default to not executing code), the executor was returning before ever writing files to disk -- the result panel would list "generated files" that didn't actually exist anywhere once the process exited. Files are now always saved regardless of whether--executewas passed. session_idwas never set, so every project's memory silently landed in one shared file regardless of directory. Memory storage is now scoped per project the same way checkpoint continuity is.--no-memorypreviously had no effect on the memory agent, which stored an entry regardless. It now correctly skips storage.
What's New in 0.2.1
This release jumps from 0.1.5 straight to 0.2.1 (0.1.6 was never published) to mark a batch of fixes serious enough that they change actual runtime behavior, not just polish: a routing/schema audit across every agent that fixes a confirmed infinite loop, closes the exact cause of the recurring "Unexpected transition" warnings, and makes memory persistence actually happen for the first time.
Critical fix
- Fixed an infinite loop in the memory agent.
memory_agentdetermined its own next step by readingnext_agentback out of the state it was just handed, rather than setting it deterministically. Since the critic agent routes to memory by settingstate["next_agent"] = "memory", and that value is still present whenmemory_agentruns, it would read back "memory", do its work, and then output "memory" again as its own next step -- routing into itself, forever, with no error and no way out short of killing the process. This was dormant until the critic-routing fix below made memory actually reachable for the first time; before that, the critic always skipped straight to "end" and this code path was never exercised.memory_agentnow always deterministically routes to "end", matching its one real edge in the graph.
Schema, prompt, and routing audit (all four agents)
Read every agent's Pydantic schema and ChatPromptTemplate end to end and cross-checked each against acra.graph.edges.GRAPH_EDGES, the graph's actual declared transitions. Found and fixed real mismatches, not just style issues:
- Coder: the prompt was internally self-contradictory -- one section listed
next_agentas "executor, critic, human", the section right below it dropped "human" and kept "critic", which the graph has never actually supported as a transition from coder. This was the exact, confirmed cause of the repeated "Unexpected transition from 'coder' to 'human'" warnings. The schema is now narrowed toexecutoronly, the coder agent deterministically setsnext_agentitself rather than trusting the model's choice, andhumanwas added to the graph's valid coder transitions for the one legitimate case (interactive approval) that still needs it. - Researcher: the prompt explicitly told the model to route to "planner" or "human", neither of which the graph supports from researcher (only "coder" is valid) -- and researcher_agent had no override at all, so any of those choices silently ended the entire workflow early. Schema narrowed to
coderonly; the agent now sets it deterministically. - Critic: the prompt said "approved -> end", and the schema didn't even list "memory" as an option -- meaning a successfully approved run could never reach memory persistence at all, despite the graph explicitly supporting it. Schema now includes "memory"; the critic agent deterministically routes based on review outcome (approved -> memory, needs_improvement/failed -> coder, unsafe -> human if interactive else back to coder for a fix attempt).
- Planner: the prompt claimed retries exceeding a safe limit route to "human", but the actual code has always deterministically routed to "critic" instead in that case -- harmless, since the code already ignores the model's own choice here, but the prompt was actively teaching an outcome that never happens. Corrected the prompt; also removed "executor" from the schema since the planner's deterministic logic never assigns it.
- Unified inconsistent internal branding ("AgentForge" in two prompts, "OMNIAGENT" in the other two) to "OmniAgent" throughout.
New features
- Task commands (
ask,build,fix,review,explain,run) now show acra's live "thought process" while a run is in progress: each agent's output streams token-by-token as it's generated, parsed on the fly into a short human-readable summary (the plan being built, research findings, which files are being written, review feedback and score) instead of raw JSON, and resolves into a clean permanent status line once that agent finishes. --memory(the default on every task command) now has real effect: acra persists a checkpoint thread per working directory and profile, so a follow-up command in the same directory continues the same project instead of starting from a blank slate.--no-memorystarts a genuinely fresh, unpersisted run every time. The new--newflag starts a separate, fresh project on demand without turning memory off going forward -- use it whenever a request in the same directory is unrelated to whatever was last built there.- Task commands no longer execute generated code by default.
build,ask,review, andexplaingenerate files without running them unless you pass--execute;fixandrunstill execute by default, since verifying a fix or literally running something is the point of those two, but--no-executeturns that off too.
Other fixes since 0.1.5
- Fixed
acra build(and every other task command) always attempting to run generated code in the Docker sandbox, even when nothing asked for it to be executed. - Fixed a major continuity bug where a follow-up command in the same directory (for example, asking to improve the UI of a project just built) had no knowledge of the previous run and could generate an unrelated project from scratch instead of continuing the existing one.
- Fixed
OmniAgentCallbacksraisingAttributeErroronon_llm_new_tokenonce real token streaming was in use, which previously flooded the terminal with callback error spam during every run. - Fixed the live "thinking" output showing raw, partially-streamed JSON syntax instead of a readable summary.
- Fixed a crash (
AttributeError: 'dict' object has no attribute 'topic') introduced by an earlier attempted fix for a LangGraph checkpoint warning:research_agent.py's existing code already converted findings/sources to plain dicts correctly further down; converting them a second time, earlier, broke that code's attribute access. Reverted to the original, correct extraction. - Fixed the checkpoint warning itself (
Deserializing unregistered type acra.schemas.critic_schema.ReviewIssue) at its actual source:critic_agent.pywas storing raw Pydantic objects directly into checkpointed state; they're now converted to plain dicts first.
What's New in 0.1.5
New features
- Provider credentials can now be stored with
acra keysand used directly by Gemini, OpenAI, Groq, and HuggingFace Cloud workflows. - The configuration wizard stores provider and research credentials outside the plaintext profile file, using the OS keyring when available and a permission-restricted local fallback otherwise.
- Long-running task and research commands show a live progress spinner.
- Task and research results are rendered as readable summaries, findings, sources, and generated-file lists instead of raw workflow state.
- Commands launched from the interactive shell now stream their output live.
Bug fixes
- Fixed saved provider keys not being read by LLM initialization.
- Fixed profile setup writing API and research keys to plaintext configuration.
- Fixed interactive-shell commands buffering output until completion.
- Fixed unwieldy raw dictionary and message-object output after task or research runs.
Requirements
- Python
>=3.11 - At least one supported LLM provider or local inference backend
- Optional: Docker, if you use execution paths that run generated projects in containers
Installation
Install the base package:
pip install acra-cli
Install provider-specific extras as needed:
pip install "acra-cli[openai]"
pip install "acra-cli[groq]"
pip install "acra-cli[ollama]"
pip install "acra-cli[huggingface]"
Install checkpointing extras:
pip install "acra-cli[sqlite]"
pip install "acra-cli[postgres]"
Install multiple extras together:
pip install "acra-cli[openai,groq,sqlite]"
After installation, run:
acra
or:
python -m acra
Quick Start
Configure a provider:
export LLM_PROVIDER=gemini
export GOOGLE_GEMINI_API_KEY="your-key"
Start the interactive shell:
acra
Create a local configuration profile:
acra config init
Show the active profile:
acra config show
Store a key in your OS keyring:
acra keys set GEMINI_API_KEY
Run a research workflow:
acra research research "Compare LangGraph and CrewAI for code-generation workflows"
The repeated research research is intentional in the current CLI: the first research is the command group and the second research is the subcommand.
Provider Configuration
acra reads provider settings from environment variables. Select the active backend with:
export LLM_PROVIDER=gemini
Supported values:
geminiopenaigroqollamahuggingface_localhuggingface_cloud
Common optional setting:
export LLM_TEMPERATURE=0.6
Gemini
Gemini support is included in the base package dependencies.
export LLM_PROVIDER=gemini
export GEMINI_MODEL=gemini-2.5-flash
export GOOGLE_GEMINI_API_KEY="your-key"
GEMINI_API_KEY is also accepted as a fallback credential variable.
OpenAI
pip install "acra-cli[openai]"
export LLM_PROVIDER=openai
export OPENAI_MODEL=gpt-4o-mini
export OPENAI_API_KEY="your-key"
Groq
pip install "acra-cli[groq]"
export LLM_PROVIDER=groq
export GROQ_MODEL=llama-3.3-70b-versatile
export GROQ_API_KEY="your-key"
Ollama
pip install "acra-cli[ollama]"
export LLM_PROVIDER=ollama
export OLLAMA_MODEL=mistral
export OLLAMA_BASE_URL=http://localhost:11434
Make sure Ollama is running:
ollama serve
HuggingFace Cloud
pip install "acra-cli[huggingface]"
export LLM_PROVIDER=huggingface_cloud
export HF_MODEL=mistralai/Mistral-7B-Instruct-v0.1
export HF_API_KEY="your-token"
HuggingFace Local
pip install "acra-cli[huggingface]"
export LLM_PROVIDER=huggingface_local
export HF_MODEL=mistralai/Mistral-7B-Instruct-v0.1
export HF_DEVICE=cpu
Use HF_DEVICE=cuda for compatible GPU environments.
Configuration Profiles
Profiles are stored in:
~/.acra/config.json
Create or update the default profile:
acra config init
Create a named profile:
acra config init --profile work
Show a profile:
acra config show
acra config show --profile work
The setup wizard prompts for:
- provider
- model
- provider API key
- theme
- workspace path
- research API keys
Key Management
acra can store credentials in your operating system keyring.
Set a key interactively:
acra keys set OPENAI_API_KEY
Set a key directly:
acra keys set OPENAI_API_KEY "your-key"
List key status:
acra keys list
Delete a key:
acra keys delete OPENAI_API_KEY
Supported provider key names are GEMINI_API_KEY, OPENAI_API_KEY, GROQ_API_KEY, and HF_API_KEY. Keys are stored in your OS keyring when it is available. On systems without a keyring backend, acra uses a local credentials file with owner-only permissions.
Research key names:
acra keys set research.web
acra keys set research.github
acra keys set research.docs
acra keys set research.arxiv
Environment fallback variables:
GEMINI_API_KEYorGOOGLE_GEMINI_API_KEYOPENAI_API_KEYGROQ_API_KEYHF_API_KEYACRA_RESEARCH_WEB_KEYACRA_RESEARCH_GITHUB_KEYACRA_RESEARCH_DOCS_KEYACRA_RESEARCH_ARXIV_KEY
CLI Usage
Run the top-level help after installation:
acra --help
Global options include:
--profile--workspace--no-memory--dry-run--json--verbose/-v--quiet/-q--timeout
Interactive Shell
Running acra without a subcommand starts the shell:
acra
You can also launch it explicitly:
acra serve
Inside the shell, type commands such as:
config show
keys list
research research "What are good approaches for agent memory?"
memory list
session list
graph show
exit
Research
Run:
acra research research "What is the best architecture for a local-first AI coding agent?"
Options:
--depth:shallow,standard, ordeep--sources: comma-separated source list--format:citations,summary, ordetailed--output: write output to a file--save: persist research output into memory--follow-up: keep the session open for follow-up questions--no-memory: skip memory persistence--profile: select a profile--json: output JSON--verbose/-v: show detailed output
Examples:
acra research research "Survey Python sandboxing options" --depth deep
acra research research "Compare ChromaDB and FAISS for agent memory" \
--sources web,github,arxiv \
--format detailed \
--output research-report.md
acra research research "LangGraph checkpointing options" \
--format summary \
--json
Task Commands
ask, build, fix, review, explain, and run all run the same underlying planner → researcher → coder → executor → critic workflow; they differ only in the label shown in the result panel, not in behavior.
acra ask "how many moons are in our solar system"
acra build "a Flask app that tracks reading habits"
acra fix "the login endpoint returns 500 on empty passwords"
acra review "the auth module for security issues"
acra explain "how the checkpoint system works"
acra run "the data migration script"
Common options on every task command:
-
--profile: profile to use -
--memory/--no-memory(default--memory): whether this run continues the checkpointed project/conversation for the current directory and profile, or starts completely fresh. See "Continuity Between Commands" below. -
--new: start a fresh project/thread in this directory instead of continuing the last one, without turning--memoryoff going forward. Use this whenever the request is unrelated to whatever was last built here. -
--interactive: route agent approval requests to a human-in-the-loop prompt -
--execute/--no-execute: whether to actually run the generated project in the Docker sandbox afterward. Defaults differ by command:Command Default Reasoning build--no-executeGenerating a project doesn't require running it ask--no-executeA question doesn't need code execution review--no-executeReviewing doesn't need re-running explain--no-executeExplaining doesn't need execution fix--executeVerifying the fix is usually the point run--executeThat's what "run" means Pass
--executeor--no-executeexplicitly to override any command's default.
Execution, when it happens, always runs inside a locked-down Docker container (no network, dropped capabilities, memory/PID limits). Docker must be installed and the invoking user must have permission to use it; without that, --execute will fail with a Docker connection error rather than silently falling back to running code on the host.
Continuity Between Commands
With --memory (the default), acra persists a checkpoint thread per (profile, working directory) pair. Running acra build "..." and then, from the same directory, acra ask "improve the ui" will give the second command the first one's generated files and project context to work from, instead of starting a new, unrelated project.
This continuity is directory-scoped, not request-scoped: acra does not try to detect whether a new request is actually related to the last one. Running two unrelated acra build commands back to back from the same directory will make the second one try to continue/patch the first project instead of starting the new one you asked for. Pass --new on the second command whenever the request is a different project, not a follow-up:
acra build "a money manager app"
acra build "an indian restaurant ordering app" --new # unrelated -- needs --new
acra build "add a dashboard to that" # follow-up -- no --new needed
Use --no-memory on a specific command for a one-off run that doesn't touch or read the persisted thread at all, or run from a different directory to keep projects separated automatically.
Configuration:
acra config init
acra config show
Keys:
acra keys set GEMINI_API_KEY
acra keys list
acra keys delete GEMINI_API_KEY
Memory:
acra memory list
acra memory search "previous docker error"
acra memory clear
Sessions:
acra session list
acra session resume <session-id>
Graph:
acra graph show
acra graph run
Note: memory, session, and graph command groups are currently available but include placeholder handlers in this beta release. The underlying Python modules are more complete than the current CLI wrappers.
Python Usage
The package exposes reusable workflow and configuration modules.
Run the compiled LangGraph workflow:
from acra.graph.workflow import OmniAgentCallbacks, create_workflow
workflow = create_workflow()
result = workflow.invoke(
{
"user_request": "Build a small Python CLI that validates JSON files",
"interactive": False,
"retry_count": 0,
"max_retries": 5,
},
config={"callbacks": [OmniAgentCallbacks()]},
)
print(result)
Use the LLM factory:
from acra.agents.llm import llm
model = llm()
response = model.invoke("Say hello in one sentence.")
print(response.content if hasattr(response, "content") else response)
Load a profile:
from acra.config.profile_manager import ProfileManager
profile = ProfileManager().load_profile()
print(profile)
Use JSON memory:
from acra.agents.memory.memory_manager import get_memory_manager
memory = get_memory_manager("example-session")
memory.add_memory(
"workflow_result",
{
"user_request": "Create a CLI",
"execution_success": True,
"quality_score": 8.5,
},
)
print(memory.get_recent_memories(limit=3))
Data Locations
Profile configuration:
~/.acra/config.json
Application data is stored in a platform-specific user data directory resolved with platformdirs.
Override it with:
export OMNIAGENT_DATA_DIR=/path/to/acra-data
Important subdirectories:
credentials.json: permission-restricted credential fallback when no OS keyring is availableprojects/: generated project filesmemory/storage/: JSON memory filesmemory/chroma_db/: ChromaDB vector memorymemory/checkpoints/data/: workflow checkpoint data
Current Beta Notes
- The package version is
0.2.2. - The top-level CLI currently attaches
serve,config,keys,research,memory,session,graph, andworkspace. - The codebase contains additional command modules such as
brain,context,logs, andplugin, but they are not currently attached to the top-level CLI. - Some CLI command groups return placeholder output while the Python modules behind them continue to evolve.
Troubleshooting
Missing provider dependency
Install the matching extra:
pip install "acra-cli[openai]"
pip install "acra-cli[groq]"
pip install "acra-cli[ollama]"
pip install "acra-cli[huggingface]"
Missing API key
Set the provider key:
export GOOGLE_GEMINI_API_KEY="your-key"
export OPENAI_API_KEY="your-key"
export GROQ_API_KEY="your-key"
export HF_API_KEY="your-token"
Or store it with:
acra keys set GEMINI_API_KEY
Ollama connection failure
Start Ollama and make sure the model is available:
ollama serve
ollama pull mistral
Then configure:
export LLM_PROVIDER=ollama
export OLLAMA_MODEL=mistral
export OLLAMA_BASE_URL=http://localhost:11434
License
acra-cli is licensed under the GNU Affero General Public License v3.
Package Metadata
- PyPI package name:
acra-cli - Console command:
acra - Python import package:
acra - Version:
0.2.2 - Python:
>=3.11 - Console script:
acra=acra.cli:app_main - Author: Raj Tembe
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file acra_cli-0.2.2.tar.gz.
File metadata
- Download URL: acra_cli-0.2.2.tar.gz
- Upload date:
- Size: 204.9 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/7.0.0 CPython/3.12.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
1dfdfd0f0aa900fb8896fa7a440c9ad344288dbfed77998624135000ea3c41ac
|
|
| MD5 |
3d37ff4931642eaa63490a8fdf222136
|
|
| BLAKE2b-256 |
dea4177cd8223f93a83e28142a027f4b0417ad304ff63b27b3ef996a065ef8ab
|
File details
Details for the file acra_cli-0.2.2-py3-none-any.whl.
File metadata
- Download URL: acra_cli-0.2.2-py3-none-any.whl
- Upload date:
- Size: 257.2 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/7.0.0 CPython/3.12.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
3c529da94792796f95347efb7064fc3509a2b4f69d6db5750ea8f141ef2419c2
|
|
| MD5 |
90c2753fbff5e7eb06e0ed53ab5d50b6
|
|
| BLAKE2b-256 |
c6a48b56851b180722350c59cdf2d5c1a4f582b4b4e014bad6d026df9517f479
|