Update description

This commit is contained in:
curo1305
2026-05-19 14:28:37 +02:00
parent b3851a2715
commit 01655124b5
2 changed files with 51 additions and 18 deletions
+43 -10
View File
@@ -1,7 +1,7 @@
# Pyra
A personal AI assistant CLI with vault-first security. Combines multi-provider AI chat with
long-term memory and (coming) automation skills.
A personal AI assistant CLI with vault-first security. Combines multi-provider AI chat,
long-term memory, and an extensible plugin system.
## Quick Start
@@ -31,6 +31,11 @@ pyra chat # start talking
| `pyra memory read <name>` | Read a memory file |
| `pyra memory write <name> <content>` | Write a memory file |
| `pyra memory append <name> <content>` | Append to a memory file |
| `pyra plugin list` | List installed and available plugins |
| `pyra plugin install <name>` | Install a bundled plugin |
| `pyra plugin enable <name>` | Enable an installed plugin |
| `pyra plugin disable <name>` | Disable a plugin (keeps it installed) |
| `pyra plugin setup <name>` | Run a plugin's credential setup wizard |
### In-chat slash commands
@@ -38,6 +43,7 @@ pyra chat # start talking
|---------|-------------|
| `/help` | Show available commands |
| `/memory list` | List memory files |
| `/config` | Open the configuration TUI |
| `/clear` | Clear conversation history |
| `/quit` or `/exit` | Exit Pyra |
@@ -48,16 +54,33 @@ pyra chat # start talking
- **Prompt injection scanner** — warns on suspicious AI output, logs to `~/.pyra/security.log`
- **Path sandboxing** — the AI can only reference memory files by name; traversal is blocked
## Plugins
Pyra has an extensible plugin system. Bundled plugins are shipped with Pyra and installed on
demand; third-party plugins can be dropped into `~/.pyra/plugins/` directly.
Each plugin is a directory containing a `manifest.json` and a `plugin.py`. Plugin credentials
are stored in the vault under namespaced keys (`plugin:<name>:<key>`) — never in `config.yaml`.
```bash
pyra plugin list # see what's available
pyra plugin install <name> # copy a bundled plugin to ~/.pyra/plugins/
pyra plugin setup <name> # enter credentials (stored in vault)
pyra plugin enable <name> # activate for the next chat session
```
## Memory
Pyra reads your memory files at the start of each session and injects them as context.
Files are plain Markdown stored in `~/.pyra/memory/`:
Files are plain Markdown stored in `~/.pyra/memory/`, indexed by a SQLite full-text search
database (`memory.db`) for fast in-chat lookup.
```
~/.pyra/memory/
├── user/profile.md ← who you are
├── context/ ← ongoing projects
── knowledge/ ← general notes
── knowledge/ ← general notes
└── memory.db ← FTS5 search index (auto-managed)
```
## `~/.pyra/` Directory
@@ -67,15 +90,25 @@ Files are plain Markdown stored in `~/.pyra/memory/`:
├── config.yaml ← provider + model (no secrets)
├── security.log ← injection event log
├── memory/ ← AI-readable long-term memory
├── skills/ ← automation scripts (Stage 2)
│ └── memory.db ← SQLite FTS5 search index
├── plugins/ ← installed plugins
│ └── <name>/
│ ├── manifest.json
│ └── plugin.py
├── logs/ ← execution logs
│ ├── tool_executions.log
│ └── plugin_errors.log
└── vault/ ← secure, AI-inaccessible storage
└── secrets/api_keys.json
```
## Roadmap
- **Stage 1** (now): Core CLI, multi-provider chat, memory, vault security
- **Stage 2**: Skills — shell/PowerShell/Python automations with user approval gates
- **Stage 3**: Vault encryption with `age`
- **Stage 4**: Security audit sub-agent
- **Stage 5**: Web UI, embedding-based memory search
- **Stage 1** Core CLI multi-provider chat, memory, vault security
- **Stage 2** ✅ Plugin Framework — extensible tools, slash commands, approval gates
- **Stage 3** ✅ Memory Database — SQLite + FTS5 full-text search index
- **Stage 4** Vault Encryption — `age`-based encryption of `~/.pyra/vault/secrets/`
- **Stage 5** Skills System — YAML-defined multi-plugin workflows with event triggers
- **Stage 6** Daemon + Messaging Bots — always-on asyncio daemon, Matrix/Telegram/Signal bots
- **Stage 7** Security Audit Sub-agent — automated scanning for injection, CVEs, permission drift
- **Stage 8** Web UI — optional local interface, embedding-based memory search
+8 -8
View File
@@ -174,7 +174,7 @@ def plugin_install(name: str) -> None:
install_bundled_plugin(name, bundled_dir, plugins_dir)
console.print(f"[green]Installed:[/green] {name}")
console.print(f" Enable: [dim]pyra plugin enable {name}[/dim]")
console.print(f" Confirm: [dim]pyra plugin setup {name}[/dim]")
console.print(f" Configure: [dim]pyra plugin setup {name}[/dim]")
except FileNotFoundError as exc:
console.print(f"[red]Error:[/red] {exc}")
except Exception as exc:
@@ -269,40 +269,40 @@ def daemon() -> None:
@daemon.command("start")
def daemon_start() -> None:
"""Start the Pyra daemon in the background."""
console.print("[yellow]Daemon (Stage 2.4) is not yet implemented.[/yellow]")
console.print("[yellow]Daemon (Stage 6) is not yet implemented.[/yellow]")
@daemon.command("stop")
def daemon_stop() -> None:
"""Stop the running Pyra daemon."""
console.print("[yellow]Daemon (Stage 2.4) is not yet implemented.[/yellow]")
console.print("[yellow]Daemon (Stage 6) is not yet implemented.[/yellow]")
@daemon.command("status")
def daemon_status() -> None:
"""Show daemon status."""
console.print("[yellow]Daemon (Stage 2.4) is not yet implemented.[/yellow]")
console.print("[yellow]Daemon (Stage 6) is not yet implemented.[/yellow]")
@daemon.command("restart")
def daemon_restart() -> None:
"""Restart the Pyra daemon."""
console.print("[yellow]Daemon (Stage 2.4) is not yet implemented.[/yellow]")
console.print("[yellow]Daemon (Stage 6) is not yet implemented.[/yellow]")
@daemon.command("install")
def daemon_install() -> None:
"""Install Pyra as a system service (launchd/systemd)."""
console.print("[yellow]Daemon service install (Stage 2.4) is not yet implemented.[/yellow]")
console.print("[yellow]Daemon service install (Stage 6) is not yet implemented.[/yellow]")
@daemon.command("uninstall")
def daemon_uninstall() -> None:
"""Remove the Pyra system service."""
console.print("[yellow]Daemon service uninstall (Stage 2.4) is not yet implemented.[/yellow]")
console.print("[yellow]Daemon service uninstall (Stage 6) is not yet implemented.[/yellow]")
@daemon.command("run", hidden=True)
def daemon_run() -> None:
"""Run daemon in foreground (used by service manager)."""
console.print("[yellow]Daemon (Stage 2.4) is not yet implemented.[/yellow]")
console.print("[yellow]Daemon (Stage 6) is not yet implemented.[/yellow]")