Metadata-Version: 2.4
Name: acra-cli
Version: 0.2.1
Summary: Agentic CLI for LLM task execution, research, and workflow automation.
Author: Raj Tembe
License: GNU Affero General Public License v3
Keywords: cli,agent,llm,langgraph,autonomous,research
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: Environment :: Console
Classifier: License :: OSI Approved :: GNU Affero General Public License v3
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Software Development :: Libraries :: Application Frameworks
Classifier: Topic :: Utilities
Requires-Python: >=3.11
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: langgraph>=0.2.0
Requires-Dist: langchain>=0.3.0
Requires-Dist: langchain-core>=0.3.0
Requires-Dist: langchain-google-genai>=2.0.0
Requires-Dist: google-generativeai>=0.8.0
Requires-Dist: pydantic>=2.0.0
Requires-Dist: python-dotenv>=1.0.0
Requires-Dist: platformdirs>=4.0.0
Requires-Dist: chromadb>=0.5.0
Requires-Dist: arxiv>=2.1.0
Requires-Dist: tavily-python>=0.3.0
Requires-Dist: google-search-results>=2.4.0
Requires-Dist: PyGithub>=2.3.0
Requires-Dist: langsmith>=0.1.0
Requires-Dist: typer[all]>=0.9.0
Requires-Dist: rich>=13.0.0
Requires-Dist: prompt_toolkit>=3.0.0
Requires-Dist: keyring>=24.0.0
Provides-Extra: openai
Requires-Dist: langchain-openai>=0.1.0; extra == "openai"
Provides-Extra: groq
Requires-Dist: langchain-groq>=0.1.0; extra == "groq"
Provides-Extra: ollama
Requires-Dist: langchain-ollama>=0.1.0; extra == "ollama"
Provides-Extra: huggingface
Requires-Dist: langchain-huggingface>=0.0.1; extra == "huggingface"
Requires-Dist: transformers>=4.30.0; extra == "huggingface"
Requires-Dist: torch>=2.0.0; extra == "huggingface"
Provides-Extra: postgres
Requires-Dist: langgraph-checkpoint-postgres>=3.1.0; extra == "postgres"
Requires-Dist: psycopg2-binary>=2.9.0; extra == "postgres"
Provides-Extra: sqlite
Requires-Dist: langgraph-checkpoint-sqlite>=3.1.0; extra == "sqlite"
Provides-Extra: test
Requires-Dist: pytest>=8.0.0; extra == "test"
Dynamic: license-file
Dynamic: requires-python

# 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.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_agent` determined its own next step by reading `next_agent` back out of the state it was just handed, rather than setting it deterministically. Since the critic agent routes to memory by setting `state["next_agent"] = "memory"`, and that value is still present when `memory_agent` runs, 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_agent` now 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_agent` as "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 to `executor` only, the coder agent deterministically sets `next_agent` itself rather than trusting the model's choice, and `human` was 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 `coder` only; 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-memory` starts a genuinely fresh, unpersisted run every time. The new `--new` flag 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`, and `explain` generate files without running them unless you pass `--execute`; `fix` and `run` still execute by default, since verifying a fix or literally running something is the point of those two, but `--no-execute` turns 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 `OmniAgentCallbacks` raising `AttributeError` on `on_llm_new_token` once 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.py` was 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 keys` and 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:

```bash
pip install acra-cli
```

Install provider-specific extras as needed:

```bash
pip install "acra-cli[openai]"
pip install "acra-cli[groq]"
pip install "acra-cli[ollama]"
pip install "acra-cli[huggingface]"
```

Install checkpointing extras:

```bash
pip install "acra-cli[sqlite]"
pip install "acra-cli[postgres]"
```

Install multiple extras together:

```bash
pip install "acra-cli[openai,groq,sqlite]"
```

After installation, run:

```bash
acra
```

or:

```bash
python -m acra
```

## Quick Start

Configure a provider:

```bash
export LLM_PROVIDER=gemini
export GOOGLE_GEMINI_API_KEY="your-key"
```

Start the interactive shell:

```bash
acra
```

Create a local configuration profile:

```bash
acra config init
```

Show the active profile:

```bash
acra config show
```

Store a key in your OS keyring:

```bash
acra keys set GEMINI_API_KEY
```

Run a research workflow:

```bash
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:

```bash
export LLM_PROVIDER=gemini
```

Supported values:

- `gemini`
- `openai`
- `groq`
- `ollama`
- `huggingface_local`
- `huggingface_cloud`

Common optional setting:

```bash
export LLM_TEMPERATURE=0.6
```

### Gemini

Gemini support is included in the base package dependencies.

```bash
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

```bash
pip install "acra-cli[openai]"

export LLM_PROVIDER=openai
export OPENAI_MODEL=gpt-4o-mini
export OPENAI_API_KEY="your-key"
```

### Groq

```bash
pip install "acra-cli[groq]"

export LLM_PROVIDER=groq
export GROQ_MODEL=llama-3.3-70b-versatile
export GROQ_API_KEY="your-key"
```

### Ollama

```bash
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:

```bash
ollama serve
```

### HuggingFace Cloud

```bash
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

```bash
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:

```text
~/.acra/config.json
```

Create or update the default profile:

```bash
acra config init
```

Create a named profile:

```bash
acra config init --profile work
```

Show a profile:

```bash
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:

```bash
acra keys set OPENAI_API_KEY
```

Set a key directly:

```bash
acra keys set OPENAI_API_KEY "your-key"
```

List key status:

```bash
acra keys list
```

Delete a key:

```bash
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:

```bash
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_KEY` or `GOOGLE_GEMINI_API_KEY`
- `OPENAI_API_KEY`
- `GROQ_API_KEY`
- `HF_API_KEY`
- `ACRA_RESEARCH_WEB_KEY`
- `ACRA_RESEARCH_GITHUB_KEY`
- `ACRA_RESEARCH_DOCS_KEY`
- `ACRA_RESEARCH_ARXIV_KEY`

## CLI Usage

Run the top-level help after installation:

```bash
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:

```bash
acra
```

You can also launch it explicitly:

```bash
acra serve
```

Inside the shell, type commands such as:

```text
config show
keys list
research research "What are good approaches for agent memory?"
memory list
session list
graph show
exit
```

### Research

Run:

```bash
acra research research "What is the best architecture for a local-first AI coding agent?"
```

Options:

- `--depth`: `shallow`, `standard`, or `deep`
- `--sources`: comma-separated source list
- `--format`: `citations`, `summary`, or `detailed`
- `--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:

```bash
acra research research "Survey Python sandboxing options" --depth deep
```

```bash
acra research research "Compare ChromaDB and FAISS for agent memory" \
  --sources web,github,arxiv \
  --format detailed \
  --output research-report.md
```

```bash
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.

```bash
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 `--memory` off 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-execute` | Generating a project doesn't require running it |
  | `ask` | `--no-execute` | A question doesn't need code execution |
  | `review` | `--no-execute` | Reviewing doesn't need re-running |
  | `explain` | `--no-execute` | Explaining doesn't need execution |
  | `fix` | `--execute` | Verifying the fix is usually the point |
  | `run` | `--execute` | That's what "run" means |

  Pass `--execute` or `--no-execute` explicitly 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:

```bash
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:

```bash
acra config init
acra config show
```

Keys:

```bash
acra keys set GEMINI_API_KEY
acra keys list
acra keys delete GEMINI_API_KEY
```

Memory:

```bash
acra memory list
acra memory search "previous docker error"
acra memory clear
```

Sessions:

```bash
acra session list
acra session resume <session-id>
```

Graph:

```bash
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:

```python
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:

```python
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:

```python
from acra.config.profile_manager import ProfileManager

profile = ProfileManager().load_profile()
print(profile)
```

Use JSON memory:

```python
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:

```text
~/.acra/config.json
```

Application data is stored in a platform-specific user data directory resolved with `platformdirs`.

Override it with:

```bash
export OMNIAGENT_DATA_DIR=/path/to/acra-data
```

Important subdirectories:

- `credentials.json`: permission-restricted credential fallback when no OS keyring is available
- `projects/`: generated project files
- `memory/storage/`: JSON memory files
- `memory/chroma_db/`: ChromaDB vector memory
- `memory/checkpoints/data/`: workflow checkpoint data

## Current Beta Notes

- The package version is `0.2.1`.
- The top-level CLI currently attaches `serve`, `config`, `keys`, `research`, `memory`, `session`, `graph`, and `workspace`.
- The codebase contains additional command modules such as `brain`, `context`, `logs`, and `plugin`, 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:

```bash
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:

```bash
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:

```bash
acra keys set GEMINI_API_KEY
```

### Ollama connection failure

Start Ollama and make sure the model is available:

```bash
ollama serve
ollama pull mistral
```

Then configure:

```bash
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.1`
- Python: `>=3.11`
- Console script: `acra=acra.cli:app_main`
- Author: Raj Tembe
