- 🤖 LLM usage: $0.0595 (3 commits)
- 👤 Human dev: ~$953 (9.5h @ $100/h, 30min dedup)
Generated on 2026-08-29 using openrouter/qwen/qwen3-coder-next
Subactor Shell jest trwałą warstwą rozmowy i orkiestracji dla terminala oraz klientów ACP. Wersja 0.2.2 integruje pytania operacyjne z zarządzanym CLI Subactora, poprawia obsługę kończenia sesji i nie przejmuje nazwy Founder Chat.
polecenie użytkownika
→ exact/template/phrase match (0 tokenów)
→ lokalny lub tani parser NL → IntentIR v1
→ lokalna walidacja JSON Schema
→ deterministyczny ExecutionPlan
→ policy + capability/connector preflight
→ nazwany connector
→ krótki ExecutionReceipt
→ duży LLM tylko przy niepewności lub zadaniu konwersacyjnym
Pełny transcript nadal jest zapisywany w SQLite, ale provider rozmowy dostaje tylko ograniczony WorkingState, kilka ostatnich wiadomości, krótką informację o trasie oraz lokalnie wybrane fragmenty danych i artefaktów.
- lokalny fast path bez LLM dla znanych poleceń;
- typowany i walidowany
IntentIR v1zamiast swobodnego planowania w prozie; - routing: deterministic/cache → local 4B → cheap remote → large/chat provider;
ExecutionPlantworzony wyłącznie przez lokalny kompilator;- nazwane connectory
builtin, Subactor Control, process oraz HTTP; - brak
shell=Truei brak możliwości wskazania przez model dowolnej komendy; - plan hash, fingerprint stanu i jawne
EXECUTEdla operacji zmieniających stan; ExecutionReceiptzamiast przekazywania pełnych logów między modelami;- telemetria tokenów, cached input, szacowanego kosztu i udziału tras bez LLM;
- trwałe sesje, jawne dane, artefakty oraz referencje Vault;
- ACP v1 po
stdin/stdout, wraz z rozszerzeniami katalogu, planów, receiptów i metryk; - migracja istniejącej bazy 0.1 bez usuwania sesji ani wiadomości.
Mac / Linux:
curl -fsSL https://subactor.github.io/shell/install.sh | shWindows:
powershell -ExecutionPolicy ByPass -c "irm https://subactor.github.io/shell/install.ps1 | iex"Instalator domyślnie pobiera metadane z
subactor.github.io/shell i w razie
problemu przechodzi na
GitHub Releases. Aby wymusić
GitHub Releases:
curl -fsSL https://subactor.github.io/shell/install.sh | SUBACTOR_SHELL_INSTALLER_USE_GITHUB_IO=false sh$env:SUBACTOR_SHELL_INSTALLER_USE_GITHUB_IO='false'; irm https://subactor.github.io/shell/install.ps1 | iexWymagania: Python 3.11+. Instalator tworzy izolowane środowisko w
~/.local/share/subactor-shell/venv i linkuje subactor-shell do
~/.local/bin.
Pakiet instaluje wyłącznie polecenie subactor-shell. Nazwa subactor jest
zarezerwowana dla Founder Chat dostarczanego przez Platformę, dzięki czemu
subactor chat zachowuje swój interfejs, pełną diagnostykę i kontrakt sesji.
Powłokę z trwałym stanem, Vault, lokalnym routingiem i ACP uruchamia się
jawnie przez subactor-shell chat.
Z wheel:
python -m venv .venv
. .venv/bin/activate
pip install ./subactor_shell_bridge-0.2.0-py3-none-any.whl
subactor-shell initZe źródeł:
python -m venv .venv
. .venv/bin/activate
pip install -e .
subactor-shell initDomyślne lokalizacje:
~/.config/subactor-shell/config.toml
~/.local/share/subactor-shell/subactor-shell.sqlite3
~/.local/share/subactor-shell/artifacts/
Katalog danych otrzymuje tryb 0700, a config, SQLite i artefakty 0600, o ile system plików wspiera te tryby.
subactor-shell chatPrzykładowe polecenia w REPL:
pokaż sesje
pokaż zużycie tokenów
/status
/plans
/receipts
/catalog
/connectors
/route
Jedna wiadomość bez REPL:
subactor-shell one 'pokaż sesje'Przy znanym intencie read-only wynik może zostać wykonany lokalnie bez wywołania providera rozmowy.
Minimalna konfiguracja lokalnego parsera OpenAI-compatible:
[orchestration]
enabled = true
mode = "active"
local_parser_provider = "local_4b"
local_parser_model = "local-4b-instruct"
cheap_parser_provider = ""
large_provider = ""
top_k = 5
max_parser_output_tokens = 192
[providers.local_4b]
kind = "openai_compat"
base_url = "http://127.0.0.1:8000/v1"
endpoint = "/chat/completions"
auth_required = false
api_key_ref = ""
model = "local-4b-instruct"
max_output_tokens = 192
structured_mode = "json_schema"Tani i duży fallback można dodać jako kolejne profile:
[orchestration]
local_parser_provider = "local_4b"
cheap_parser_provider = "budget_remote"
large_provider = "planner_remote"
[providers.budget_remote]
kind = "openai_compat"
base_url = "https://provider.example/v1"
endpoint = "/chat/completions"
api_key_ref = "env://BUDGET_LLM_API_KEY"
auth_required = true
model = "budget-model"
max_output_tokens = 192
structured_mode = "json_schema"
input_cost_per_million = 0.0
cached_input_cost_per_million = 0.0
output_cost_per_million = 0.0
[providers.planner_remote]
kind = "openai_compat"
base_url = "https://provider.example/v1"
endpoint = "/chat/completions"
api_key_ref = "env://PLANNER_LLM_API_KEY"
auth_required = true
model = "large-planner"
max_output_tokens = 800
structured_mode = "json_schema"Stawki w configu są wyłącznie danymi użytkownika do lokalnego szacowania kosztu. Projekt nie pobiera automatycznie cenników.
Tryby orkiestracji:
active— wykonuje poprawne lokalne plany;shadow— zapisuje routing i IntentIR, ale odpowiedź nadal prowadzi provider rozmowy;off— zachowanie konwersacyjne bez DSL.
Model parsera może zwrócić tylko obiekt zgodny z schemas/intent-ir.v1.schema.json, na przykład:
{
"v": 1,
"intent_id": "project.deploy",
"mode": "plan",
"args": {
"project_ref": "project://docs",
"environment": "prod"
},
"requirements": ["verify_tls"],
"constraints": ["no_secret_export"],
"unresolved": []
}Model nie wybiera komendy, ścieżki wykonywalnej, URL, connectora ani secret ref. Te elementy pochodzą z lokalnego katalogu intentów i konfiguracji connectorów.
Wbudowane intenty obejmują pomoc, sesje, dane, bindingi sekretów, metryki oraz cli.status/cli.plan istniejącego Subactor Control.
Dodatkowe katalogi wskazuje się w configu:
[orchestration]
intent_catalog_paths = ["./intent-catalog.v1.json"]Przykład znajduje się w examples/intent-catalog.v1.json. Loader akceptuje własny format {"intents": [...]} oraz kilka typowych nazw pól spotykanych w intent packach, ale dokładna integracja z repozytorium nadrzędnym wymaga rzeczywistych plików JSON, nie samej mapy symboli.
[connectors.project_ops]
kind = "process"
command = ["/opt/subactor/bin/project-connector", "--json-stdin"]
allowed_operations = ["project.inspect", "project.apply"]
effect = "external_write"
inherit_env = false
pass_env = ["PATH", "LANG", "LC_ALL", "TZ"]
timeout_seconds = 30.0
output_limit_bytes = 65536
[connectors.project_ops.env_refs]
PROJECT_API_TOKEN = "vault://secret/subactor/project#token"Pierwszy element command musi być ścieżką absolutną. Runtime uruchamia stałe argv przez create_subprocess_exec, bez powłoki. Domyślnie nie dziedziczy całego środowiska procesu; przepuszcza tylko nazwy z pass_env oraz jawne env_refs. Connector dostaje JSON przez stdin:
{
"plan_id": "plan_...",
"plan_hash": "...",
"session_id": "...",
"intent_id": "project.apply",
"operation": "project.apply",
"args": {}
}Minimalny przykład implementacji: examples/process-connector.py.
[connectors.project_http]
kind = "http"
base_url = "https://connector.internal"
path = "/v1/execute"
method = "POST"
bearer_ref = "file://~/.config/subactor-shell/project-http.token"
allowed_operations = ["project.inspect", "project.apply"]
effect = "external_write"subactor_control pozostaje specjalnym connectorom z dokładną allowlistą:
[control]
allowed_tools = ["cli.status", "cli.plan", "cli.execute"]Bridge wykonuje tools/list przed wywołaniem i odrzuca endpoint, który reklamuje inny zestaw narzędzi. cli.execute wymaga zaakceptowanego planu.
Operacja read-only może wykonać się automatycznie. Operacja zmieniająca stan zapisuje plan:
subactor-shell plans list
subactor-shell plans show PLAN_ID
subactor-shell plans apply PLAN_ID --confirm EXECUTE
subactor-shell receipts list
subactor-shell receipts show RECEIPT_IDPrzed apply sprawdzane są:
- status planu;
plan_hash;- dokładne
EXECUTEdla zmian stanu; - aktualny fingerprint SQLite, katalogu intentów i registry connectorów;
- allowlista connectora i operation;
- lokalna policy.
Pełna historia jest przechowywana, lecz nie jest ponownie wysyłana przy każdej turze. Limity ustawia sekcja:
[context]
recent_messages = 6
max_history_chars = 12000
max_message_chars = 4000
max_data_chars = 6000
max_attachment_prompt_chars = 8000
artifact_chunk_chars = 1800
max_artifact_chunks = 4
max_embedded_context_chars = 8000
max_route_context_chars = 4000{{data:NAME}} i załączniki są dzielone lokalnie na fragmenty i wybierane leksykalnie względem bieżącego polecenia. Model otrzymuje tylko wynik mieszczący się w budżecie. To nie jest pełny silnik semantyczny; dla rozbudowanego repozytorium należy podłączyć istniejące DOQL/DQL lub własny retriever jako nazwany connector.
subactor-shell data set ENVIRONMENT staging
subactor-shell data put SPEC ./specification.md
subactor-shell data listW rozmowie:
Przeanalizuj ustawienia {{data:ENVIRONMENT}} oraz sekcję deployment w {{data:SPEC}}.
Jawne dane mogą zostać wysłane do providera po lokalnym wyborze fragmentów. Nie należy zapisywać w tej warstwie sekretów.
Binding zapisuje wyłącznie referencję:
subactor-shell vault bind DB_PASSWORD 'vault://secret/subactor/prod/database#password'Zapis wartości do Vault KV v2 pobiera ją bez echa:
subactor-shell vault put DB_PASSWORD 'vault://secret/subactor/prod/database#password'W REPL:
/vault grant DB_PASSWORD
Sprawdź format {{secret:DB_PASSWORD}}, ale jej nie powtarzaj.
Grant jest jednorazowy i przechowywany wyłącznie w pamięci procesu. Placeholder w zapisanych danych, pliku lub embedded resource ACP nie może sam zużyć grantu. Lokalne fast path nie odczytuje sekretu i nie konsumuje grantu.
subactor-shell metrics --json
subactor-shell metrics --session SESSION_ID --jsonWynik obejmuje:
- liczbę wywołań providerów;
- input, cached input i output tokens;
- wywołania z usage oszacowanym lokalnie;
- koszt według stawek wpisanych w configu;
- rozkład tras;
- udział tras
deterministicicachebez LLM.
subactor-shell acp-agentOprócz ACP v1 (initialize, session/new, session/load, session/prompt, session/cancel) agent obsługuje rozszerzenia:
subactor/data/set
subactor/data/list
subactor/secret/bind
subactor/secret/grant
subactor/secret/list
subactor/catalog/list
subactor/connectors/list
subactor/route/get
subactor/metrics/get
subactor/plan/list
subactor/plan/get
subactor/plan/apply
subactor/receipt/list
subactor/receipt/get
subactor/plan/apply używa tej samej walidacji i wymaga pola confirmation: "EXECUTE" dla zmian stanu. stdout procesu ACP jest zarezerwowany dla jednoliniowych komunikatów JSON-RPC.
Po wskazaniu istniejącego --data-dir Store automatycznie dodaje tabele:
session_state
routing_decisions
provider_usage
execution_plans
execution_receipts
router_feedback
context_cache
Istniejące sessions, messages, artifacts, jawne dane i bindingi sekretów pozostają zachowane. Przed migracją produkcyjną zalecana jest kopia pliku SQLite.
python -m pip install -e '.[dev]'
pytest -qPakiet wydaniowy 0.2.0 został sprawdzony testami jednostkowymi i integracyjnymi oraz instalacją wheel do izolowanego katalogu pakietów, uruchomioną poza drzewem źródeł. Integracje z prawdziwymi kontami Vault/LLM/Subactor należy dodatkowo sprawdzić w docelowym środowisku.
Więcej szczegółów:
docs/TOKEN_ROUTING.md— routing, WorkingState i budżety;docs/INTEGRATION.md— dopasowanie do aktualnej mapy repozytorium Subactor;SECURITY.md— granice zaufania i model zagrożeń;CHANGELOG.md— zakres wersji 0.2.0.
Licensed under Apache-2.0.