rubik 0.2.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (42) hide show
  1. checksums.yaml +4 -4
  2. data/ATTRIBUTION.md +4 -0
  3. data/CHANGELOG.md +81 -0
  4. data/README.md +137 -268
  5. data/bin/rubik +9 -0
  6. data/lib/rubik/cli/workspace_trust.rb +78 -0
  7. data/lib/rubik/kernel/init.rb +15 -0
  8. data/lib/rubik/orchestrator/auto_apply.rb +1 -1
  9. data/lib/rubik/orchestrator/subagent/activation.rb +29 -4
  10. data/lib/rubik/orchestrator/subagent/builtin_types.rb +117 -0
  11. data/lib/rubik/orchestrator/subagent/dynamic_store.rb +119 -0
  12. data/lib/rubik/orchestrator/subagent/instance.rb +8 -36
  13. data/lib/rubik/orchestrator/subagent/journal.rb +77 -4
  14. data/lib/rubik/orchestrator/subagent/profile_contract.rb +187 -0
  15. data/lib/rubik/orchestrator/subagent/profile_snapshot.rb +72 -0
  16. data/lib/rubik/orchestrator/subagent/reuse.rb +2 -1
  17. data/lib/rubik/orchestrator/subagent/scoped_registry.rb +2 -0
  18. data/lib/rubik/orchestrator/subagent/spawn_transaction.rb +170 -0
  19. data/lib/rubik/orchestrator/subagent/start_gate.rb +98 -0
  20. data/lib/rubik/orchestrator/subagent/supervisor.rb +4 -67
  21. data/lib/rubik/orchestrator/subagent/type_definition.rb +84 -0
  22. data/lib/rubik/orchestrator/subagent/type_registry.rb +139 -159
  23. data/lib/rubik/orchestrator/turn_executor/subagent_channel.rb +4 -2
  24. data/lib/rubik/platform/process.rb +78 -1
  25. data/lib/rubik/prompt/context_builder.rb +54 -20
  26. data/lib/rubik/prompt/doctrine.rb +158 -22
  27. data/lib/rubik/prompt/token_estimator.rb +5 -3
  28. data/lib/rubik/prompt/tool_teachings.rb +19 -12
  29. data/lib/rubik/sandbox/driver/bubblewrap.rb +13 -59
  30. data/lib/rubik/sandbox/driver/docker.rb +14 -60
  31. data/lib/rubik/sandbox/driver/podman.rb +13 -56
  32. data/lib/rubik/sandbox/driver/process.rb +12 -64
  33. data/lib/rubik/security/guard.rb +1 -1
  34. data/lib/rubik/storage/store.rb +52 -11
  35. data/lib/rubik/tools/builtins/define_subagent.rb +69 -0
  36. data/lib/rubik/tools/builtins/storage.rb +8 -5
  37. data/lib/rubik/tools/builtins/subagent.rb +20 -53
  38. data/lib/rubik/tools/builtins/synthesis.rb +6 -1
  39. data/lib/rubik/tools/builtins.rb +1 -0
  40. data/lib/rubik/tools/diagnostic_reporter.rb +2 -1
  41. data/lib/rubik/version.rb +1 -1
  42. metadata +10 -1
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b9f5ba8b65658f3899e0ade863faf5f64a11c80a4c43d18f5230e3248bd215ae
4
- data.tar.gz: 2132bc4a2fb1927a6a94fa8869a384bb2ca5c1d93f5d45e630fef394a42299b4
3
+ metadata.gz: 14020218aa50674cdf508953465d4f31c285420979b8a9c518ef4d5e6f6ef300
4
+ data.tar.gz: caa28cd931b29aecf1de25e66d794a304f04ea0331e9b58f2b198c985488a8e2
5
5
  SHA512:
6
- metadata.gz: 6de6f5477ca7fbee7099efec31dce72e44f3fb95a2a69b891f252e1c88d794be5e3a4139c3077197527c05c2fe2de3d5971229dad2da7e91c8a0802503243a71
7
- data.tar.gz: 42c0c6074a7e8902e98bae63f0fe0b45b04a0a7f83cc68b3e63f12a2a88075ba768debb551b1837269c0baf69ac8435b86534bb7c612da91e9f91073388eda28
6
+ metadata.gz: 27fdbf68f5e00c88e87bdfe3ba33e837783b3b4a573ae3ccbd8db707fd7b320af8256c5a875811d33feaaf2118f18c701579266bdb2795d27815d0d0199d30b7
7
+ data.tar.gz: d050ff897cbe97a68399a31a28ca68e53f7edf7e894e097bbba338f722406975f397cd5fcd3fe21946c98d5c6a8a158f7193c04979d7878dcd985cdc524083b0
data/ATTRIBUTION.md CHANGED
@@ -146,3 +146,7 @@ SOFTWARE.
146
146
 
147
147
  Rubik itself is licensed under the **MIT License**.
148
148
  See the [`LICENSE`](LICENSE) file for the full license text.
149
+
150
+ ---
151
+
152
+ See the [documentation index](docs/index.md) or return to the [README](README.md).
data/CHANGELOG.md CHANGED
@@ -10,6 +10,87 @@ The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
10
10
 
11
11
  Nothing yet.
12
12
 
13
+ ## [0.3.0] - 2026-10-18
14
+
15
+ The subagent-governance minor: runtime-defined archetypes become
16
+ context-scoped and reversible, spawn turns transactional, outcomes
17
+ are measured, and the first interactive launch asks before trusting
18
+ a workspace. Prompt teachings and tool schemas are aligned against
19
+ the declared contracts.
20
+
21
+ ### Added
22
+
23
+ - **Context-scoped, reversible archetype registration (#175, closes
24
+ #171):** runtime `define_subagent` profiles are owned by an explicit
25
+ runtime context with LIFO revision stacks and context-bound disposal
26
+ inverses — disposing the owner pops the registration and restores
27
+ the prior profile; stale out-of-order cleanups remove only what they
28
+ own; built-ins stay reserved; re-registering a live archetype
29
+ requires `replace: true`; and nested profiles are owned and cleaned
30
+ up by the child context.
31
+ - **Workspace trust prompt (#183, closes #182):** interactive launches
32
+ in an untrusted workspace show the resolved path, explain Rubik's
33
+ file and command capabilities and the `buffer.model_can_apply:
34
+ false` limitation, and offer a per-workspace Trust and continue or
35
+ Exit choice (exit is the default); script and non-interactive
36
+ launches do not block on the prompt.
37
+ - **Validated subagent profile contracts (#177, closes #172):** custom
38
+ archetypes declare required coeffects and allowlisted capability
39
+ grants; profiles default to no write or nested-spawn grants; invalid
40
+ names, dependencies, grants and field limits return structured
41
+ validation errors before registration; custom tool filters derive
42
+ only from allowlisted grants.
43
+ - **Subagent profile outcomes and bounded prompt visibility (#179,
44
+ closes #174):** root prompts keep every built-in and show only the
45
+ eight newest active custom profiles; run journals record profile
46
+ identity and version, outcome, bounded redacted error summaries,
47
+ duration, step and tool-call counts, and provider-reported token
48
+ usage — missing token and cost data are marked unavailable, never
49
+ estimated.
50
+
51
+ ### Fixed
52
+
53
+ - **Subagent spawn is transactional (#178, closes #173):** required
54
+ coeffects are validated before the worker starts; a startup failure
55
+ rolls back the child context, scoped registry, kernel registration,
56
+ instance and generated ID; each instance pins an immutable profile
57
+ snapshot (redeploys keep the original); and honest spawn failures
58
+ reach the maestro.
59
+ - **The system prompt follows active tools and mode (#170, closes
60
+ #166):** teachings for gated tools are filtered when their
61
+ coeffects are unsatisfied, plan-only mode directs no tool calls or
62
+ synthesis, and read-only orientation vs delegated execution is
63
+ harmonized across rules and role headers.
64
+ - **Storage and Vakanüvis write rules are aligned (#169, closes
65
+ #165):** direct `storage put` targets work artifacts
66
+ (goal/plan/review/note) while durable `memory` cards and `wiki`
67
+ pages route through `vakanuvis` record/digest when available; the
68
+ tool declaration documents the contract and the coder prompt
69
+ surfaces durable lessons to the maestro.
70
+ - **Tool teachings match declared schemas (#168, closes #167):**
71
+ `replace_file_content` guidance drops the unadvertised aliases
72
+ (runtime tolerance preserved) and `synthesize_tool` requires
73
+ `params_schema` when the synthesized tool accepts arguments.
74
+
75
+ ### Changed
76
+
77
+ - **Documentation navigation:** user and developer guides reorganized
78
+ under `docs/`, README quickstart and feature summary refreshed, and
79
+ GitHub issue and pull request templates plus a code of conduct
80
+ added; provider and local model IDs refreshed across README,
81
+ configuration, command, API and first-session examples.
82
+ - **Process stream capture is consolidated (#180):**
83
+ `Rubik::Platform.popen_capture` centralizes Open3 startup,
84
+ concurrent stdout/stderr capture, exit-status mapping and timeout
85
+ process-tree termination; ProcessDriver, Bubblewrap, Docker and
86
+ Podman drivers share it.
87
+ - **Hot paths get cheaper:** `TokenEstimator.estimate_text` switches
88
+ to exact integer math with zero allocations (~7.8% on history
89
+ estimation, #181); `Store#search_ranked` ranking cuts allocations
90
+ by ~43% (#176).
91
+ - **Deps:** `tree_sitter_language_pack` bumps to 1.22.1 (#162); dev
92
+ rubocop to 1.92.0 (#163).
93
+
13
94
  ## [0.2.0] - 2026-10-16
14
95
 
15
96
  The first minor of the 0.2 era is a hardening minor: a reproducible
data/README.md CHANGED
@@ -1,297 +1,166 @@
1
- # 🎲 Rubik — Autonomous AI Coding Agent & REPL Harness
1
+ # Rubik
2
2
 
3
3
  English | [Türkçe](README.tr.md)
4
4
 
5
- > A next-generation autonomous pair-programming and REPL harness written in pure Ruby, built on the **Spatiotemporal Composability & Self-Evolving Runtime** architecture.
5
+ [![Build](https://github.com/ozgurulukir/rubik/actions/workflows/ci.yml/badge.svg?branch=main)](https://github.com/ozgurulukir/rubik/actions/workflows/ci.yml)
6
+ [![Gem version](https://img.shields.io/gem/v/rubik.svg)](https://rubygems.org/gems/rubik)
7
+ [![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)
8
+ [![Ruby 3.4+](https://img.shields.io/badge/ruby-3.4%2B-red.svg)](https://www.ruby-lang.org/)
9
+ [![Coverage reports](https://img.shields.io/badge/coverage-CI%20artifacts-blue.svg)](https://github.com/ozgurulukir/rubik/actions/workflows/ci.yml)
10
+ [![Test Suite](https://img.shields.io/badge/tests-see%20CI-blue.svg)](https://github.com/ozgurulukir/rubik/actions/workflows/ci.yml)
6
11
 
7
- [![Gem Version](https://img.shields.io/gem/v/rubik.svg)](https://rubygems.org/gems/rubik)
8
- [![Gem Downloads](https://img.shields.io/gem/dt/rubik.svg)](https://rubygems.org/gems/rubik)
9
- [![Ruby Version](https://img.shields.io/badge/ruby-3.4%2B-red.svg)](https://www.ruby-lang.org)
10
- [![Platform](https://img.shields.io/badge/platform-Linux%20%7C%20macOS%20%7C%20Windows-blue.svg)](https://github.com/ozgurulukir/rubik/actions/workflows/ci.yml)
11
- [![Protocol](https://img.shields.io/badge/protocol-AGENTS.md-blue.svg)](AGENTS.md)
12
- [![Commands Guide](https://img.shields.io/badge/docs-COMMANDS.md-yellow.svg)](COMMANDS.md)
13
- [![Config Guide](https://img.shields.io/badge/docs-CONFIG.md-green.svg)](CONFIG.md)
14
- [![CI](https://github.com/ozgurulukir/rubik/actions/workflows/ci.yml/badge.svg?branch=main)](https://github.com/ozgurulukir/rubik/actions/workflows/ci.yml)
15
- [![Test Suite](https://img.shields.io/badge/tests-3696%20runs%20%7C%20verified%202026--10--15-brightgreen.svg)](https://github.com/ozgurulukir/rubik/actions/workflows/ci.yml)
12
+ ## About
16
13
 
17
- ---
14
+ Rubik is a Ruby terminal coding agent and interactive REPL. It connects an LLM to
15
+ workspace tools for reading and changing code, while staging file edits in a
16
+ reviewable in-memory buffer. Developers can use it as a CLI or embed its runtime
17
+ from Ruby with `require "rubik"`.
18
18
 
19
- ## 👋 What is Rubik?
19
+ Rubik is for developers who want an agent in their terminal and control over how
20
+ its changes reach disk. It supports OpenAI-compatible providers, Anthropic, and
21
+ local Ollama. Its security checks and optional OS sandbox are described in
22
+ [Security](SECURITY.md).
20
23
 
21
- Rubik is a terminal-native autonomous coding agent and interactive REPL in pure Ruby. A **maestro** agent orchestrates specialized subagents (research / coder / self) over a 34-tool belt: file edits stage in a virtual in-memory buffer (`!diff` → `!apply`, with configurable model authority and auto-apply policies), managed runtime side effects register LIFO inverses to support dynamic reloads and teardowns without process restarts, and failing services can be diagnosed and repaired live. It supports Linux, macOS, and Windows across a bounded CI matrix, connects to OpenAI-compatible endpoints, Anthropic, or local Ollama, and the runtime is embeddable from Ruby with `require "rubik"`.
24
+ ## Quickstart
22
25
 
23
- ---
26
+ **Prerequisites:** Ruby 3.4 or later and an OpenRouter API key for this example.
27
+ The gem is the shortest install path:
24
28
 
25
- ## 🚀 Quick Start
26
-
27
- ### From the gem
28
-
29
- Requires **Ruby 3.4+**:
30
-
31
- CI tests Linux on Ruby 3.4 (minimum) and 4.0, and macOS and Windows on
32
- Ruby 4.0. Each job installs dependencies, runs the full unit/integration suite,
33
- and builds, installs and smokes the gem (`rubik --version` and `require "rubik"`).
34
- See [CI runs](https://github.com/ozgurulukir/rubik/actions/workflows/ci.yml)
35
- for results on a specific commit; platform artifacts contain environment details,
36
- installation/smoke logs, test counts and skip reasons. Other Ruby/OS combinations
37
- are not covered by this bounded matrix.
38
-
39
-
40
- ```bash
29
+ ```sh
41
30
  gem install rubik
42
31
  ```
43
32
 
44
- The installer puts the `rubik` launcher into RubyGems' bin directory (already on your `PATH`), so you can start it from any project directory:
45
-
46
- ```bash
47
- rubik
48
- ```
49
-
50
- or with Bundler:
51
-
52
- ```ruby
53
- gem "rubik"
54
- ```
55
-
56
- #### Platform notes
57
-
58
- | Platform | Install experience |
59
- | :--- | :--- |
60
- | 🐧 Linux / 🍎 macOS | `gem install rubik` — dependencies ship prebuilt. |
61
- | 🪟 Windows | `tree_sitter_language_pack` has no Windows prebuilt and compiles from source: install Rust with the GNU toolchain and export `RUST_TARGET=x86_64-pc-windows-gnu` before installing. The exact, working recipe is [`.github/workflows/ci.yml`](.github/workflows/ci.yml). |
62
-
63
- ### From source
64
-
65
- **Prerequisites**
66
-
67
- - **Ruby:** 3.4.0 or later (`ruby -v`)
68
- - **Linux / macOS:** Via the system package manager, `rbenv`, `rvm`, or `asdf`.
69
- - **Windows:** [Scoop](https://scoop.sh) (`scoop install ruby`) or [RubyInstaller with DevKit](https://rubyinstaller.org).
70
- - **Git:** Git 2.30+ (`git -v`)
71
- - **LLM Provider:** Local [Ollama](https://ollama.ai) (`ollama run qwen2.5-coder:7b`) or a DeepSeek, OpenRouter, Anthropic, or OpenAI API key.
72
-
73
- Clone the project, install the dependencies, and start the REPL:
74
-
75
- ```bash
76
- git clone https://github.com/ozgurulukir/rubik.git
77
- cd rubik
78
- bundle install
79
- ```
80
-
81
- #### 🐧 Linux & 🍎 macOS (POSIX)
33
+ Set the key in your shell, then start Rubik. Replace the example value with your
34
+ key:
82
35
 
83
- ```bash
84
- # Proje dizininden doğrudan çalıştırma
85
- ./bin/rubik
86
-
87
- # Veya sistemde global kullanmak için ~/.local/bin dizinine bağlayın:
88
- ln -sf $(pwd)/bin/rubik ~/.local/bin/rubik
36
+ ```sh
37
+ export OPENROUTER_API_KEY="your-key"
89
38
  rubik
90
39
  ```
91
40
 
92
- > [!NOTE]
93
- > **The gem and a clone can coexist.** On POSIX the symlink always runs your clone: `bin/rubik` resolves `lib/` from its own real path, so a `git pull` is live on the very next launch — even while the `rubik` gem stays installed. The gem-installed `rubik` keeps serving the last released version until you run `gem update rubik`. On Windows, whichever `bin` folder comes first in `PATH` wins — `where.exe rubik` shows the winner.
94
-
95
- #### 🪟 Windows (PowerShell / Command Prompt)
96
-
97
- Rubik ships with built-in `.cmd`, `.bat`, and `.ps1` wrappers for Windows:
41
+ In PowerShell:
98
42
 
99
43
  ```powershell
100
- # PowerShell üzerinden çalıştırma
101
- .\bin\rubik.ps1
102
-
103
- # veya Command Prompt / Terminal üzerinden
104
- .\bin\rubik.cmd
105
-
106
- # veya Ruby üzerinden doğrudan
107
- ruby bin\rubik
44
+ $env:OPENROUTER_API_KEY = "your-key"
45
+ rubik
108
46
  ```
109
47
 
110
- > [!TIP]
111
- > **The Global `rubik` Command on Windows:**
112
- > By adding Rubik's `bin` folder to your environment variables (User PATH), you can launch it from any terminal simply by typing `rubik`:
113
- > ```powershell
114
- > [Environment]::SetEnvironmentVariable("PATH", "$env:PATH;$PWD\bin", "User")
115
- > ```
48
+ At the REPL prompt, register the provider and choose a model:
116
49
 
117
- ### Adding a Provider & Model
50
+ <!-- markdownlint-disable MD013 -->
118
51
 
119
- You can connect any OpenAI-compatible provider in a single line:
120
-
121
- ```bash
122
- # REPL içerisinden sağlayıcı ekleme:
123
- rubik > !provider add deepseek openai_compatible https://api.deepseek.com/v1/chat/completions --key=sk-... --model=deepseek-coder --context=64000
124
- rubik > !model deepseek/deepseek-coder
52
+ ```text
53
+ !provider add openrouter openai_compatible https://openrouter.ai/api/v1/chat/completions --key-env=OPENROUTER_API_KEY --model=anthropic/claude-sonnet-5.5 --context=200000 -g
54
+ !model openrouter/anthropic/claude-sonnet-5.5
125
55
  ```
126
56
 
127
- Anthropic talks over its **native Messages API** (not an OpenAI shim): the `anthropic` provider is registered out of the box — set `ANTHROPIC_API_KEY` and pick a model:
128
-
129
- ```bash
130
- rubik > !model anthropic/claude-sonnet-5-5
131
- ```
57
+ <!-- markdownlint-enable MD013 -->
132
58
 
133
- ### First Session Example
59
+ Then enter a prompt at the REPL:
134
60
 
135
61
  ```text
136
- ╭── rubik ─────────────────────────────────────────────────╮
137
- │ 🎲 Rubik v0.1.0 │
138
- │ deepseek/deepseek-coder │
139
- │ my_project · main │
140
- │ !help komutlar · ctrl+c kes · !config ayarlar │
141
- ╰──────────────────────────────────────────────────────────╯
142
- deepseek/deepseek-coder · ctx 3% · temiz · sandbox kapalı
143
- rubik (my_project) [main] > !status
144
- Project: my_project (main)
145
- Default Model: deepseek/deepseek-coder
146
- Dirty buffer: false
147
-
148
- rubik (my_project) [main] > Kullanıcı kayıt formunu doğrulayan bir helper fonksiyonu yaz
149
- ✻ Düşünüyor… · 1s (ctrl+c: kes)
150
- ⏺ write_file — lib/validator.rb
151
- ⎿ 3 lines · 18ms
152
-
153
- [Rubik] In-memory buffer updated. Type `!diff` to view, `!apply` to save.
154
-
155
- rubik (my_project) [main] [DIRTY: 1 ✎] > !diff
156
- + def validate_user(params)
157
- + raise "Invalid email" unless params[:email]&.include?("@")
158
- + end
159
-
160
- rubik (my_project) [main] [DIRTY: 1 ✎] > !test
161
- Applied 1 file(s) before test. All 12 tests passed!
62
+ Summarize the files in this project.
162
63
  ```
163
64
 
164
- > [!TIP]
165
- > **Safe Execution (Tree-Sitter AST) & Pluggable OS Isolation (Bubblewrap / Container):**
166
- >
167
- > Before running any command, Rubik keeps the `Security::Guard` shield active (Safe Execution), which detects dangerous commands, pipeline poisoning, and directory escapes ahead of time via Tree-Sitter syntax-tree (AST) analysis for Bash and PowerShell plus a database of 172 CLI YAML rules. The command gate fails closed on unrecognized syntax or classifier errors. Hardware-enforced OS isolation is optional and disabled by default (`sandbox.enabled: false`); enabling it on Linux requires Bubblewrap (`bwrap`) or OCI containers (`docker`/`podman`):
168
- > ```bash
169
- > !sandbox on # Enables hardware/container OS isolation on Linux
170
- > !config set sandbox.allow_network true -p # Grants outbound network access within the sandbox
171
- > ```
172
-
173
- ---
174
-
175
- ## ⚡ Key Features
176
-
177
- - 🌐 **Cross-Platform Support (Linux, macOS, Windows):** Supports Windows 11 / Windows Server environments (PowerShell, Command Prompt, Windows Terminal) alongside POSIX systems (Linux, macOS). Uses pure-Ruby binary resolution, NTFS case-insensitivity handling, RFC 8089 LSP URIs, and native Windows CLI (`.cmd`, `.bat`, `.ps1`) wrappers. Verified against CI's bounded matrix (Windows gem installation compiles `tree_sitter_language_pack` from source using the Rust GNU toolchain; see [.github/workflows/ci.yml](.github/workflows/ci.yml)).
178
- - 🛡️ **In-Memory Virtual Buffer & Staged Writes:** When the model writes code, file changes stage in an in-memory virtual buffer before touching disk. You can inspect changes with `!diff`, apply them with `!apply`, or discard unapplied buffer edits with `!undo`.
179
- - **Authority & Review Gates:** Staging alone does not enforce manual human review. By default, `buffer.auto_apply: manual` stages changes, but `buffer.model_can_apply: true` allows the model to flush its own edits via the `apply_buffer` tool. To guarantee human operator review before any disk modification, set `buffer.model_can_apply: false` alongside `buffer.auto_apply: manual`. When `buffer.auto_apply` is set to `on_test`, `on_finish`, or `always`, the runtime automatically flushes dirty buffer edits to disk at trigger boundaries.
180
- - **Atomic File Writes vs Multi-File Transactions:** Each individual file write is atomic (written to a temporary file and atomically renamed/replaced), but applying changes across multiple files is not an all-or-nothing multi-file transaction. If an error occurs midway (e.g. permission error or containment block), previously written files remain on disk while failed and pending files stay dirty in the buffer with a structured partial report (`applied`, `failed`, `pending`, `conflicts`).
181
- - 🏢 **Multi-Workspace & Extra Root Directories:** In monorepo or sibling-package layouts (`../shared-kernel`, `../proto`), you can safely attach external root directories (`!workspace add`) and include them in the buffer and the AST index in read-only or writable (`--rw`) mode.
182
- - ⚡ **Live LSP Compiler Diagnostics:** When configured language server binaries (`rust-analyzer`, `gopls`, `ruff`, `typescript-language-server`, `typeprof`, etc.) are installed on the host `PATH`, Rubik connects over stdio JSON-RPC to feed compiler diagnostics back to the agent after edits. Language servers are external dependencies; if a server binary is missing, unconfigured, or fails the handshake, Rubik falls back to syntax and AST analysis without blocking the session (see [LSP.md](LSP.md)).
183
- - 🌳 **Multilingual Tree-Sitter & Prism Hybrid AST Engine:** Employs built-in **Prism** for Ruby and **Tree-Sitter** grammars for Python, Go, Rust, TypeScript, TSX, JavaScript, C, C++, and Zig to avoid string/comment lexical confusion during symbol parsing. If Tree-Sitter grammars or C extensions are unavailable or encounter parse errors, the engine falls back to legacy regex extractors (which have known structural limits with complex or nested code). The symbol and call graph (`!symbols`, `!outline`, `!refs`) scans asynchronously in the background and leverages an on-disk cache (`.rubik/cache/ast_index.json`) to minimize cold-start indexing overhead across restarts; cold and warm timings for a 150-file synthetic Ruby fixture are recorded in [_report/runtime-capacity-validation-2026-10-16.md](_report/runtime-capacity-validation-2026-10-16.md).
184
- - 🤖 **Dynamic LLM Providers & Multi-Role Routing:** Light/heavy task routing with support for all OpenAI-compatible endpoints (DeepSeek, Groq, OpenRouter, Mistral, vLLM), Anthropic Claude, OpenAI, and local Ollama.
185
- - 🧬 **Spatiotemporal Composability & Self-Evolving Runtime:** The model can synthesize new REPL commands (`synthesize_command`) or built-in tools (`synthesize_tool`) at runtime; managed runtime effects registered through the context are unwound with LIFO inverses ($\Omega$).
186
- - 🩹 **Self-Healing Runtime (Service Repair Plane):** Runtime components never require a process restart. `inspect_runtime` exposes the live fiber/coeffect/service state; `repair_runtime_service` diagnoses a failing component (LSP server, test runner, linter, or shell command), probes replacement commands with pre-flight verification in an isolated sub-context, and re-provides the repaired service — session state, caches, and conversations stay intact. `provide_service` registers new services live. Repair probes are bounded and disposable; failed promotion or persistence restores session state. Successfully saved operator configuration survives lifecycle cleanup. See [runtime repair](RUNTIME_REPAIR.md) for probe and rollback contracts.
187
- - 📋 **Structured Goal Ledger (SKILL.state adaptation):** the `!goal` loop keeps a rev-guarded ΔΣ ledger (objective, tasks, findings, decisions, open questions, environment notes) instead of trusting lossy conversation memory. The maestro patches it with the root-only `update_goal_ledger` tool (classified syntax/schema/conflict feedback, bounded retries), the current Σ is pinned through every compaction tier and re-injected each step, every revision is appended to storage (`goal-ledger` ref), declarative `verify` specs are re-checked at step boundaries (a failed check flips the task to `stale` — the world-drift signal), and banked tool results compact into per-row `<absorbed_into_ledger>` tombstones. Default ON (`goal.ledger.*`, operator-only; opt-out per key).
188
- - 🧹 **Context Pruner (Semi-Deterministic Window Cleanup):** Long sessions accumulate stale exploration in the maestro's conversation window. A Vakanüvis-style two-plane pruner cleans it: a silent LLM subagent proposes a keep/drop/summarize plan, and the harness validates it deterministically (goal pinning, tool-use pairing, head/tail preservation bands, token budget) and applies it atomically at the next turn boundary — never mid-turn. It auto-fires at 60% of the input ceiling (before the blind drop-oldest trimmer would) or on demand via the `prune_context` tool and `!prune`. Default ON since 2026-10-10 (`subagents.pruner.*`, operator-only; opt-out `enabled: false`); the deterministic compaction stack always remains the safety net.
189
- - 🔌 **Drop-in Plugin System (User Plugins):** Drop-in `.rb` files or package directories under `~/.rubik/plugins` (global) or `.rubik/plugins` (project) load dynamically (`!plugin add`, `!plugin reload`). Integrity is gated by SHA-256 digests in `.manifest.json` (full package tree for directory plugins). Plugins execute arbitrary Ruby in the host process; manifests protect against untracked or modified files, but do not sandbox plugin runtime behavior. Foreign repositories without a manifest require explicit review or operator consent (`RUBIK_BOOTSTRAP_OVERLAYS=1` / `RUBIK_TRUST_OVERLAYS=1`). See [PLUGINS.md](PLUGINS.md).
190
- - 🔌 **Model Context Protocol (MCP) & Spatiotemporal Tool Isolation:** Dynamically attaches external MCP servers (`filesystem`, `fetch`, databases, GitHub, etc.) over the stdio transport (`!mcp connect`, `!mcp add`). Discovered tools join the registry as `Rubik::Tools::BaseTool` proxies; server termination triggers registered LIFO cleanup inverses ($\Omega$) for child processes and proxy tools; these inverses help prevent orphan processes and stale tool calls when cleanup completes successfully. The cleanup path was exercised across 1,000 normal, handshake-failure, and crash/recovery cycles with explicit resource tolerances; see [_report/runtime-capacity-validation-2026-10-16.md](_report/runtime-capacity-validation-2026-10-16.md).
191
- - 📺 **Tiered Live Agent Monitoring (Step Formatter & Verbosity):** With the `quiet`, `normal`, `verbose`, and `debug` levels, step progress, tool calls, execution times, and intermediate thoughts are watched in real time (`!verbosity`, `!verbose`).
192
- - 🎨 **Hybrid TUI Display Layer:** The `⏺/⎿` agent flow language, a live spinner cycling through Turkish verbs (`✻ Kavuruyor… 4sn`), an above-prompt statusline (model · context percentage · dirty buffer), live markdown rendering, a colored diff viewer, one-key quick approvals, and the interactive `!agents` fiber board. Under `NO_COLOR`/`--no-color` and in pipe mode the output degrades to plain text; session logs never contain ANSI codes (live settings via `!config set ui.*`).
193
- - ⚡ **Native Tool Acceleration:** When available on the system, `grep_search` is delegated to ripgrep and context scanning to `git ls-files`; AST symbols warm up with lazy body loading. Without rg/git, or with `tools.native: off` or `RUBIK_NATIVE=off`, every path falls back to pure Ruby with identical output — the output format never changes.
194
- - 🧵 **Quiet Concurrency (Fiber Scheduler Event Loop):** The pure-stdlib `Rubik::Concurrency` layer provides cooperative single-threaded concurrency WITHOUT altering any existing blocking I/O call sites (Net::HTTP, sleep, Open3 pipes, Mutex/CV/Thread#join): tested at 100 and 1,000 concurrent local network requests, including latency, timeout, cancellation, and sequential comparisons; see [_report/runtime-capacity-validation-2026-10-16.md](_report/runtime-capacity-validation-2026-10-16.md)), the MCP boot fan-out, and the subagent provider pool all run through the `Concurrency.silently`/`.map` boundary (not CPU parallelism, due to the GVL). Kill switch: `RUBIK_FIBER_SCHEDULER=off`.
195
- - 📜 **Vakanüvis Chronicler (Session Annals):** The deterministic harness records REPL root turns and subagent lifecycle events into the `rubik://storage` annals; a budget-capped LLM distiller mines memory and a wiki skeleton from those annals. All planes are governed by `subagents.vakanuvis.*`; chronicles can be recalled through the Vakanüvis tool (`recall`/`record`/`forget`/`digest`).
196
-
197
- > 🛡️ **Security note — when cloning unfamiliar repositories:** The `.rubik/commands` and `.rubik/tools` directories contain overlay files that can be interpreted at runtime. SHA-256 manifest verification blocks later modifications; files carrying a sentinel header but no manifest are accepted on the first scan only with the explicit consent of `RUBIK_BOOTSTRAP_OVERLAYS=1`. If you have cloned a repository you do not know, inspect the `.rubik/` directory before the first run.
198
-
199
- ---
200
-
201
- ## 🕹️ REPL Bang Commands
202
-
203
- For detailed parameters, flags, and usage scenarios of all 30+ interactive commands:
204
- 👉 Check out the **[COMMANDS.md — Comprehensive REPL Command Guide](COMMANDS.md)** document.
205
-
206
- ### Command Summary Table
207
-
208
- | Command Group | Key Commands | Description |
209
- | :--- | :--- | :--- |
210
- | **Models & Providers** | `!provider`, `!providers`, `!model` | Provider add/remove (CRUD), model role assignment, and smart routing. |
211
- | **Agent & Planning** | `!plan`, `!goal`, `!steps` | Step-by-step planning, the autonomous goal loop, and step budget management. |
212
- | **Buffer & Snapshots** | `!diff`, `!apply`, `!autoapply`, `!undo` | Inspect the in-memory virtual file buffer, save to disk, and revert. |
213
- | **Runtime & Fibers** | `!runtime`, `!fibers`, `!services` | Coeffect services, active/pending fibers, and the $\Omega$ inverse depth. |
214
- | **Code Intelligence & LSP** | `!lsp`, `!symbols`, `!outline`, `!refs` | Compiler diagnostics and semantic AST graph searches. |
215
- | **Tests & Execution** | `!test`, `!lint`, `!format`, `!sh`, `!sandbox` | Multilingual test runs, Safe Execution, and a pluggable sandbox (bwrap/docker/podman). |
216
- | **Session & Settings** | `!session`, `!history`, `!config`, `!verbosity`, `!status` | Session persistence, resuming with `rubik -c`, verbosity, and live settings. |
217
- | **Workspace & Roots** | `!workspace`, `!roots`, `!allow` | Adding/removing multiple root directories (`add`/`remove`), external permissions (`!allow`), and status listing. |
218
-
219
- ### Agent Surface Contract
220
-
221
- Every command is typed with an `audience` at registration time: `:human` (operator only), `:agent`, or `:both`. Agent-visible built-in commands (`!diff`, `!status`, `!undo`, `!rollback`, `!autoapply`, `!context`, `!steps`, `!config`, `!model`, `!providers`, `!runtime`, `!fibers`, `!services`, `!agents`, `!lint`, `!format`, `!history`, `!prune`) are published as `<agent_commands>` in the system prompt and can be invoked via the `exec_repl_command` tool; file, code, test, and shell operations are always performed directly through the tools (`read_file`, `write_file`, `run_tests`, `run_command`). Human-only commands (`!provider`, `!workspace`, `!allow`, `!verbosity`, …) are reported back to the agent as a steering message; session lifecycle commands (`!quit`, `!exit`, `!clear`, `!reset`) are hard-blocked for the agent, while `!plan`/`!goal` are redirected to the "finish" tool behind reentrancy protection. Two notes: a `!model` switch takes effect on the next agent run; and `!undo`/`!rollback` revert buffer changes not yet applied to disk, while in `buffer.auto_apply` = `on_test`/`always` mode they may trigger the pre-run auto-apply.
222
-
223
- ---
224
-
225
- ## ⚙️ Configuration
226
-
227
- For details on all model, LSP, buffer policy, provider, and sandbox settings:
228
- 👉 Check out the **[CONFIG.md — Rubik Configuration Guide](CONFIG.md)** document.
229
-
230
- ---
231
-
232
- ## 🖥️ Agent Shell Behavior
233
-
234
- `run_command` commands are never left to an implicit interpreter: the Safe Execution infrastructure runs every command with a **resolved shell** and an explicit argv array. `sandbox.shell: auto` (the default) chooses per command via a syntax gate — bash-required syntax (`<(...)`, `/dev/null`, heredocs) and `$` substitutions go to **bash**, the PowerShell fingerprint (`$env:`, `Select-String`, `Get-*` and other cmdlets) goes to **pwsh**, and plain commands take the fast path to **cmd** on Windows (bash elsewhere). The choice is labeled in the result (`[EXIT 1] (bash)`), and the system prompt announces the shell behavior to the model up front via the `<environment>` line — the model now knows which shell it is writing commands for. Use `sandbox.shell: bash|pwsh|cmd|sh` to pin a preference (see [CONFIG.md](CONFIG.md) §7).
235
-
236
- ---
237
-
238
- ## 🧪 Test Suite
239
-
240
- Full suite: `rake` (or `rake test`). Single file: `ruby -Itest test/unit/test_repl.rb`.
241
-
242
- Windows notes:
243
- - Tests run sequentially in a single process; multi-file arguments such as `ruby -Itest a.rb b.rb` run only the **first** file — always use `rake` for the full suite.
244
- - A space-containing `TEST` value such as `rake test TEST="a b"` is interpreted as a single path on Windows; make one invocation per file.
245
- - Temp-directory removal (`teardown`) can fail with `Errno::EACCES` on Windows while a handle is still open; the `remove_temp_dir` helper in `test_helper.rb` swallows this with a best-effort retry and never muddies test results.
246
-
247
- Environmental test skips:
248
- - PowerShell shell execution tests are skipped when the `pwsh` (PowerShell Core) binary is not present on the system.
249
- - Alternative AST parser tests are skipped when the `prism` gem or its C extension is not present on the system.
250
- - In non-interactive / headless CI environments, direct TUI/reline terminal tests automatically run in non-blocking mode or are skipped in a controlled way.
251
- - Capability skips report their reasons; unexpected failures still fail CI. A passing run describes that runner and commit, not a universal platform guarantee.
252
-
253
- ---
254
-
255
- ## 📦 Versioning Policy & SemVer 2.0 (Pre-1.0 Stability Roadmap)
256
-
257
- Rubik adopts the [Semantic Versioning 2.0.0](https://semver.org/) standard. In the current pre-1.0 release (`0.1.0`), the Spatiotemporal Composability core architecture, the fiber lifecycle, and the agent protocols are being hardened:
258
- - **0.x Releases:** A phase of rapid architectural evolution and refinement of experimental capabilities. Improvements to the core APIs are managed alongside the plan documents.
259
- - **1.0.0 Goal:** Reaching production stability by freezing the core SPI interfaces, the Revertible Effects LIFO protocol, and the agent surface contract.
260
- - **Backward Compatibility:** Before every minor release, comprehensive backward-compatibility and SPI breakage analyses (using GitNexus knowledge-graph & PDG analysis) are mandatory.
261
-
262
- ---
263
-
264
- ## 📚 Documentation
265
-
266
- Every guide ships as a bilingual pair — `X.md` (English, authoritative) alongside `X.tr.md` (Turkish translation).
267
-
268
- ### Architecture & Internals
269
-
270
- | Guide | What it covers |
271
- | :--- | :--- |
272
- | 🌌 [AGENTS.md](AGENTS.md) | The Spatiotemporal Composability Protocol — theory, invariants, the fiber lifecycle state machine. |
273
- | 🏗️ [ARCHITECTURE.md](ARCHITECTURE.md) | The 30 core domains and the responsibility matrix. |
274
- | 🧬 [SELF_EVOLUTION.md](SELF_EVOLUTION.md) | How the LLM synthesizes tools, repairs services, and evolves its own runtime. |
275
- | 🔌 [API.md](API.md) | Embedding the runtime from Ruby: config, tool registry, provider contract, orchestrator loop, error contracts. |
276
-
277
- ### User & Operator Guides
278
-
279
- | Guide | What it covers |
280
- | :--- | :--- |
281
- | 🕹️ [COMMANDS.md](COMMANDS.md) | All 30+ REPL bang commands with parameters and usage scenarios. |
282
- | 🧰 [TOOLS.md](TOOLS.md) | Catalog of the 34 built-in agent tools: parameters, risk classes, diagnostics. |
283
- | ⚙️ [CONFIG.md](CONFIG.md) | Every configuration knob (models, LSP, buffer policy, sandbox, subagents, pruner…). |
284
- | 🌍 [ENV.md](ENV.md) | Environment variables — single consolidated reference table. |
285
- | 🖥️ [LSP.md](LSP.md) | Step-by-step language-server setup and diagnostics walkthrough. |
286
- | 🔌 [PLUGINS.md](PLUGINS.md) | The drop-in plugin system: layout, manifests, zero-downtime reloads. |
287
-
288
- ### Project & Policy
289
-
290
- | Guide | What it covers |
291
- | :--- | :--- |
292
- | 🤝 [CONTRIBUTING.md](CONTRIBUTING.md) | Dev setup, test commands, commit/PR conventions, security reporting. |
293
- | 🧪 [TESTING.md](TESTING.md) | Running the suite, naming conventions, test templates, flaky-test policy. |
294
- | 🔒 [SECURITY.md](SECURITY.md) | Command gate, critical-write protection, synthesis gates, sandbox, audit log. |
295
- | 📜 [ATTRIBUTION.md](ATTRIBUTION.md) | Open-source attributions and third-party notices. |
296
- | 📜 [CHANGELOG.md](CHANGELOG.md) | Thematic release history; the full record lives in `git log`. |
297
- | 📄 [LICENSE](LICENSE) | Software license (MIT). |
65
+ Use `!diff` to review staged file changes and `!apply` to write them to disk. See the
66
+ [first-session tutorial](docs/tutorials/first-session.md) for platform-specific
67
+ credential setup and a longer walkthrough. Windows gem installation may compile
68
+ a dependency from source; see the [installation guide](docs/how-to/installation.md).
69
+
70
+ > **Safety note:** Model-generated code and commands can be incorrect or unsafe. Review
71
+ > changes with `!diff` and run tests before relying on them. For strict human approval
72
+ > of **buffered file changes only**, set `buffer.auto_apply: manual` and
73
+ > `buffer.model_can_apply: false`. These settings do not gate shell commands or
74
+ > background processes: the command safety gate checks them, but allowed commands run
75
+ > without a separate per-command approval prompt. The OS sandbox is disabled by default;
76
+ > run untrusted code in an isolated environment. See [Security](SECURITY.md).
77
+
78
+ ## Features
79
+
80
+ 1. **Core · Cross-platform CLI.** Run the terminal agent and REPL on Linux,
81
+ macOS, or Windows. The CI matrix covers Ubuntu with Ruby 3.4 and 4.0, and
82
+ macOS and Windows with Ruby 4.0. In the Windows CI environment, gem
83
+ installation compiles a native dependency with the Rust GNU toolchain. See
84
+ the [installation guide](docs/how-to/installation.md).
85
+ 2. **Core · Staged file edits.** Model writes go to an in-memory virtual buffer;
86
+ inspect them with `!diff`, apply them with `!apply`, or discard unapplied
87
+ edits with `!undo`.
88
+ 3. **Core · Review control and write semantics.** To require operator approval
89
+ for buffered file changes, set `buffer.model_can_apply: false` together with
90
+ `buffer.auto_apply: manual`. This does not add approval prompts for shell
91
+ commands or background processes; see [security practices](SECURITY.md). Each
92
+ file is written atomically, but a multi-file apply is not a transaction: a
93
+ partial failure leaves the remaining changes dirty and reports applied,
94
+ failed, and pending files. See [buffer configuration](docs/how-to/configuration.md).
95
+ 4. **Core · Multiple workspace roots.** Add sibling or external directories as
96
+ read-only roots by default, or allow writes with `--rw`; additional roots can
97
+ join code search and the AST index. See the [`!workspace` commands](docs/reference/commands.md).
98
+ 5. **Core · Guarded command execution.** Commands pass through Rubik's safety
99
+ checks. Bubblewrap, Docker, or Podman isolation is optional and disabled by
100
+ default. See [security practices](SECURITY.md).
101
+ 6. **Models · Provider and role routing.** Connect OpenAI-compatible endpoints,
102
+ Anthropic, OpenAI, or local Ollama, then assign models to default, fast, and
103
+ advanced roles or use task-based routing. See [provider configuration](docs/how-to/configuration.md).
104
+ 7. **Code intelligence · Hybrid AST.** Prism parses Ruby; Tree-Sitter grammars
105
+ cover Python, Go, Rust, TypeScript, TSX, JavaScript, C, C++, and Zig. Symbol
106
+ and call-graph indexing can warm in the background and persists to a local
107
+ cache. If Tree-Sitter is unavailable, Rubik can use regex extractors, which
108
+ have structural limits. Parsing errors have structured statuses, and a
109
+ failed re-index preserves previously indexed symbols. See [architecture](docs/explanation/architecture.md).
110
+ 8. **Code intelligence · Live LSP diagnostics.** Configured language servers
111
+ can start on demand and return compiler or linter diagnostics after edits.
112
+ Missing or failing servers do not block a session; Rubik falls back to its
113
+ built-in syntax and AST analysis. See [language-server setup](docs/how-to/language-servers.md).
114
+ 9. **Code intelligence · Native fast paths.** When available, ripgrep and Git
115
+ accelerate search and context scanning; Rubik falls back to pure Ruby when
116
+ those binaries are missing or native paths are disabled. Control them through
117
+ `tools.native` or `RUBIK_NATIVE`. See [configuration](docs/how-to/configuration.md).
118
+ 10. **Extensions · Runtime synthesis.** The model can create REPL commands and
119
+ tools during a session. Managed runtime effects register cleanup actions
120
+ and unwind them in LIFO order. See [self-evolution](docs/explanation/self-evolution.md).
121
+ 11. **Extensions · Plugins.** Load or reload drop-in Ruby plugins from user or
122
+ project directories. SHA-256 manifests detect modified files, but plugins
123
+ execute arbitrary Ruby in the host process and are not sandboxed. See the
124
+ [plugin guide](docs/how-to/plugins.md).
125
+ 12. **Extensions · MCP servers.** Connect external stdio servers and expose
126
+ discovered tools through Rubik's registry. Lifecycle cleanup removes proxy
127
+ tools and attempts to stop child processes when the server is disconnected.
128
+ See [MCP commands](docs/reference/commands.md).
129
+ 13. **Recovery · Live service repair.** Inspect runtime state, verify a
130
+ replacement command in a disposable context, then promote it without
131
+ restarting the process. Failed promotion or persistence unwinds session
132
+ changes; if a previous service cannot be restored, the repair result reports
133
+ incomplete rollback. Successful operator configuration saves remain in
134
+ place. See [runtime repair](docs/explanation/runtime-repair.md).
135
+ 14. **Long sessions · Structured goal ledger.** The `!goal` loop keeps a
136
+ revision-guarded record of objectives, tasks, findings, and decisions;
137
+ current state survives compaction, and configured verification checks run
138
+ at step boundaries. See [goal commands](docs/reference/commands.md).
139
+ 15. **Long sessions · Context pruning.** A pruner can propose what to keep,
140
+ drop, or summarize; the harness validates the plan and applies it at a turn
141
+ boundary. The operator can also invoke it with `!prune`. See [pruner settings](docs/how-to/configuration.md).
142
+ 16. **Long sessions · Vakanüvis annals.** When configured, the chronicler
143
+ records session turns and subagent events; its distiller can build memory
144
+ notes and a wiki skeleton. See [runtime architecture](docs/explanation/architecture.md).
145
+ 17. **Interaction · Live monitoring and TUI.** Choose quiet, normal, verbose,
146
+ or debug output. The interface combines a statusline, spinner, Markdown
147
+ renderer, colored diff view, and interactive `!agents` board. `NO_COLOR` and
148
+ pipe mode fall back to plain text, and session logs omit ANSI codes. See
149
+ [UI configuration](docs/how-to/configuration.md).
150
+ 18. **Runtime · Cooperative I/O concurrency.** A pure-Ruby Fiber Scheduler can
151
+ overlap supported blocking I/O on one thread; it does not parallelize CPU
152
+ work; disable it with `RUBIK_FIBER_SCHEDULER=off`. The capacity harness
153
+ exercises lifecycle checks at 1,000 epochs, 100 and 1,000 concurrent loopback
154
+ requests, and AST-cache behavior. See [architecture](docs/explanation/architecture.md)
155
+ and [testing](docs/development/testing.md).
156
+
157
+ ## Documentation
158
+
159
+ Browse the [documentation index](docs/index.md) for tutorials, how-to guides,
160
+ references, architecture explanations, and development guidance. The
161
+ [changelog](CHANGELOG.md) records releases.
162
+
163
+ ## Contributing and policies
164
+
165
+ [Contributing](CONTRIBUTING.md) · [Code of Conduct](CODE_OF_CONDUCT.md) ·
166
+ [Security policy](SECURITY.md) · [License](LICENSE)
data/bin/rubik CHANGED
@@ -3,6 +3,7 @@
3
3
 
4
4
  $LOAD_PATH.unshift File.expand_path("../lib", __dir__)
5
5
  require "rubik"
6
+ require "rubik/cli/workspace_trust"
6
7
  require "optparse"
7
8
 
8
9
  # Global SIGINT safety net. The REPL installs its own "INT" handler while
@@ -60,6 +61,14 @@ OptionParser.new do |opts|
60
61
  end
61
62
  end.parse!
62
63
 
64
+ workspace_trusted = options[:script] ||
65
+ Rubik::CLI::WorkspaceTrust.authorize!(
66
+ workspace: Dir.pwd,
67
+ input: $stdin,
68
+ output: $stdout
69
+ )
70
+ Kernel.exit(0) unless workspace_trusted
71
+
63
72
  shell = Rubik::REPL::Shell.new
64
73
 
65
74
  if options[:continue]