pikuri 0.0.1 → 0.0.3

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 (51) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +31 -179
  3. data/lib/pikuri.rb +12 -162
  4. metadata +45 -159
  5. data/CHANGELOG.md +0 -62
  6. data/GETTING_STARTED.md +0 -223
  7. data/LICENSE +0 -21
  8. data/lib/pikuri/agent/chat_transport.rb +0 -41
  9. data/lib/pikuri/agent/context_window_detector.rb +0 -101
  10. data/lib/pikuri/agent/listener/in_memory_message_list.rb +0 -33
  11. data/lib/pikuri/agent/listener/message_listener.rb +0 -93
  12. data/lib/pikuri/agent/listener/step_limit.rb +0 -97
  13. data/lib/pikuri/agent/listener/terminal.rb +0 -137
  14. data/lib/pikuri/agent/listener/token_log.rb +0 -166
  15. data/lib/pikuri/agent/listener_list.rb +0 -113
  16. data/lib/pikuri/agent/message.rb +0 -61
  17. data/lib/pikuri/agent/synthesizer.rb +0 -120
  18. data/lib/pikuri/agent/tokens.rb +0 -56
  19. data/lib/pikuri/agent.rb +0 -286
  20. data/lib/pikuri/subprocess.rb +0 -166
  21. data/lib/pikuri/tool/bash.rb +0 -272
  22. data/lib/pikuri/tool/calculator.rb +0 -82
  23. data/lib/pikuri/tool/confirmer.rb +0 -96
  24. data/lib/pikuri/tool/edit.rb +0 -196
  25. data/lib/pikuri/tool/fetch.rb +0 -167
  26. data/lib/pikuri/tool/glob.rb +0 -310
  27. data/lib/pikuri/tool/grep.rb +0 -338
  28. data/lib/pikuri/tool/parameters.rb +0 -314
  29. data/lib/pikuri/tool/read.rb +0 -254
  30. data/lib/pikuri/tool/scraper/fetch_error.rb +0 -16
  31. data/lib/pikuri/tool/scraper/html.rb +0 -285
  32. data/lib/pikuri/tool/scraper/pdf.rb +0 -54
  33. data/lib/pikuri/tool/scraper/simple.rb +0 -177
  34. data/lib/pikuri/tool/search/brave.rb +0 -184
  35. data/lib/pikuri/tool/search/duckduckgo.rb +0 -196
  36. data/lib/pikuri/tool/search/engines.rb +0 -154
  37. data/lib/pikuri/tool/search/exa.rb +0 -217
  38. data/lib/pikuri/tool/search/rate_limiter.rb +0 -92
  39. data/lib/pikuri/tool/search/result.rb +0 -29
  40. data/lib/pikuri/tool/skill.rb +0 -80
  41. data/lib/pikuri/tool/skill_catalog.rb +0 -376
  42. data/lib/pikuri/tool/sub_agent.rb +0 -102
  43. data/lib/pikuri/tool/web_scrape.rb +0 -117
  44. data/lib/pikuri/tool/web_search.rb +0 -38
  45. data/lib/pikuri/tool/workspace.rb +0 -150
  46. data/lib/pikuri/tool/write.rb +0 -170
  47. data/lib/pikuri/tool.rb +0 -118
  48. data/lib/pikuri/url_cache.rb +0 -106
  49. data/lib/pikuri/version.rb +0 -10
  50. data/prompts/coding-system-prompt.txt +0 -28
  51. data/prompts/pikuri-chat.txt +0 -15
metadata CHANGED
@@ -1,234 +1,120 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: pikuri
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.0.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Martin Vysny
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2026-05-14 00:00:00.000000000 Z
11
+ date: 2026-05-22 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
- name: dentaku
14
+ name: pikuri-assistant
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - "~>"
17
+ - - '='
18
18
  - !ruby/object:Gem::Version
19
- version: '3.5'
19
+ version: 0.0.3
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
- - - "~>"
24
+ - - '='
25
25
  - !ruby/object:Gem::Version
26
- version: '3.5'
26
+ version: 0.0.3
27
27
  - !ruby/object:Gem::Dependency
28
- name: faraday
28
+ name: pikuri-code
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
- - - "~>"
31
+ - - '='
32
32
  - !ruby/object:Gem::Version
33
- version: '2.9'
33
+ version: 0.0.3
34
34
  type: :runtime
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
- - - "~>"
38
+ - - '='
39
39
  - !ruby/object:Gem::Version
40
- version: '2.9'
40
+ version: 0.0.3
41
41
  - !ruby/object:Gem::Dependency
42
- name: nokogiri
42
+ name: pikuri-core
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
- - - "~>"
45
+ - - '='
46
46
  - !ruby/object:Gem::Version
47
- version: '1.19'
47
+ version: 0.0.3
48
48
  type: :runtime
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
- - - "~>"
52
+ - - '='
53
53
  - !ruby/object:Gem::Version
54
- version: '1.19'
54
+ version: 0.0.3
55
55
  - !ruby/object:Gem::Dependency
56
- name: pdf-reader
56
+ name: pikuri-mcp
57
57
  requirement: !ruby/object:Gem::Requirement
58
58
  requirements:
59
- - - "~>"
59
+ - - '='
60
60
  - !ruby/object:Gem::Version
61
- version: '2.15'
61
+ version: 0.0.3
62
62
  type: :runtime
63
63
  prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
- - - "~>"
66
+ - - '='
67
67
  - !ruby/object:Gem::Version
68
- version: '2.15'
68
+ version: 0.0.3
69
69
  - !ruby/object:Gem::Dependency
70
- name: rainbow
70
+ name: pikuri-skills
71
71
  requirement: !ruby/object:Gem::Requirement
72
72
  requirements:
73
- - - "~>"
73
+ - - '='
74
74
  - !ruby/object:Gem::Version
75
- version: '3.1'
75
+ version: 0.0.3
76
76
  type: :runtime
77
77
  prerelease: false
78
78
  version_requirements: !ruby/object:Gem::Requirement
79
79
  requirements:
80
- - - "~>"
80
+ - - '='
81
81
  - !ruby/object:Gem::Version
82
- version: '3.1'
82
+ version: 0.0.3
83
83
  - !ruby/object:Gem::Dependency
84
- name: reverse_markdown
84
+ name: pikuri-workspace
85
85
  requirement: !ruby/object:Gem::Requirement
86
86
  requirements:
87
- - - "~>"
87
+ - - '='
88
88
  - !ruby/object:Gem::Version
89
- version: '3.0'
89
+ version: 0.0.3
90
90
  type: :runtime
91
91
  prerelease: false
92
92
  version_requirements: !ruby/object:Gem::Requirement
93
93
  requirements:
94
- - - "~>"
94
+ - - '='
95
95
  - !ruby/object:Gem::Version
96
- version: '3.0'
97
- - !ruby/object:Gem::Dependency
98
- name: ruby-readability
99
- requirement: !ruby/object:Gem::Requirement
100
- requirements:
101
- - - "~>"
102
- - !ruby/object:Gem::Version
103
- version: '0.7'
104
- type: :runtime
105
- prerelease: false
106
- version_requirements: !ruby/object:Gem::Requirement
107
- requirements:
108
- - - "~>"
109
- - !ruby/object:Gem::Version
110
- version: '0.7'
111
- - !ruby/object:Gem::Dependency
112
- name: ruby_llm
113
- requirement: !ruby/object:Gem::Requirement
114
- requirements:
115
- - - "~>"
116
- - !ruby/object:Gem::Version
117
- version: '1.15'
118
- type: :runtime
119
- prerelease: false
120
- version_requirements: !ruby/object:Gem::Requirement
121
- requirements:
122
- - - "~>"
123
- - !ruby/object:Gem::Version
124
- version: '1.15'
125
- - !ruby/object:Gem::Dependency
126
- name: tsort
127
- requirement: !ruby/object:Gem::Requirement
128
- requirements:
129
- - - "~>"
130
- - !ruby/object:Gem::Version
131
- version: '0.2'
132
- type: :runtime
133
- prerelease: false
134
- version_requirements: !ruby/object:Gem::Requirement
135
- requirements:
136
- - - "~>"
137
- - !ruby/object:Gem::Version
138
- version: '0.2'
139
- - !ruby/object:Gem::Dependency
140
- name: tty-markdown
141
- requirement: !ruby/object:Gem::Requirement
142
- requirements:
143
- - - "~>"
144
- - !ruby/object:Gem::Version
145
- version: '0.7'
146
- type: :runtime
147
- prerelease: false
148
- version_requirements: !ruby/object:Gem::Requirement
149
- requirements:
150
- - - "~>"
151
- - !ruby/object:Gem::Version
152
- version: '0.7'
153
- - !ruby/object:Gem::Dependency
154
- name: zeitwerk
155
- requirement: !ruby/object:Gem::Requirement
156
- requirements:
157
- - - "~>"
158
- - !ruby/object:Gem::Version
159
- version: '2.7'
160
- type: :runtime
161
- prerelease: false
162
- version_requirements: !ruby/object:Gem::Requirement
163
- requirements:
164
- - - "~>"
165
- - !ruby/object:Gem::Version
166
- version: '2.7'
96
+ version: 0.0.3
167
97
  description: |
168
- A library for assembling AI assistants: Pikuri::Agent (a thin wrapper around
169
- ruby_llm's chat loop), Pikuri::Tool with strict argument validation, a
170
- listener surface for rendering / budgets / sub-agents, and a small set of
171
- bundled tools (calculator, web search, web scrape, fetch, plus six coding
172
- tools: read / write / edit / grep / glob / bash). Downstream projects
173
- (notably the planned pikuri-tui) wire these into actual binaries. The repo
174
- also ships `bin/pikuri-chat` and `bin/pikuri-code` as demo entry points,
175
- but they are NOT installed by `gem install pikuri` — they exist to show
176
- how to wire the library together and to support development.
98
+ +pikuri+ is the convenience bundle for the pikuri AI-assistant
99
+ toolkit. It ships no Ruby code of its own beyond a tiny entry
100
+ file that +require+'s each sibling gem; +gem install pikuri+
101
+ pulls in pikuri-core, pikuri-skills, pikuri-workspace,
102
+ pikuri-code, pikuri-mcp, and pikuri-assistant in one shot, and
103
+ +require 'pikuri'+ boots all of them.
104
+
105
+ Privacy-conscious users who want a minimal dependency tree to
106
+ audit should install +pikuri-core+ directly and opt into the
107
+ extension gems they actually need — same +bundle add+ pattern
108
+ Rails users have always had. See each pikuri-* gem's README
109
+ for its individual surface.
177
110
  email:
178
111
  - martin@vysny.me
179
112
  executables: []
180
113
  extensions: []
181
114
  extra_rdoc_files: []
182
115
  files:
183
- - CHANGELOG.md
184
- - GETTING_STARTED.md
185
- - LICENSE
186
116
  - README.md
187
117
  - lib/pikuri.rb
188
- - lib/pikuri/agent.rb
189
- - lib/pikuri/agent/chat_transport.rb
190
- - lib/pikuri/agent/context_window_detector.rb
191
- - lib/pikuri/agent/listener/in_memory_message_list.rb
192
- - lib/pikuri/agent/listener/message_listener.rb
193
- - lib/pikuri/agent/listener/step_limit.rb
194
- - lib/pikuri/agent/listener/terminal.rb
195
- - lib/pikuri/agent/listener/token_log.rb
196
- - lib/pikuri/agent/listener_list.rb
197
- - lib/pikuri/agent/message.rb
198
- - lib/pikuri/agent/synthesizer.rb
199
- - lib/pikuri/agent/tokens.rb
200
- - lib/pikuri/subprocess.rb
201
- - lib/pikuri/tool.rb
202
- - lib/pikuri/tool/bash.rb
203
- - lib/pikuri/tool/calculator.rb
204
- - lib/pikuri/tool/confirmer.rb
205
- - lib/pikuri/tool/edit.rb
206
- - lib/pikuri/tool/fetch.rb
207
- - lib/pikuri/tool/glob.rb
208
- - lib/pikuri/tool/grep.rb
209
- - lib/pikuri/tool/parameters.rb
210
- - lib/pikuri/tool/read.rb
211
- - lib/pikuri/tool/scraper/fetch_error.rb
212
- - lib/pikuri/tool/scraper/html.rb
213
- - lib/pikuri/tool/scraper/pdf.rb
214
- - lib/pikuri/tool/scraper/simple.rb
215
- - lib/pikuri/tool/search/brave.rb
216
- - lib/pikuri/tool/search/duckduckgo.rb
217
- - lib/pikuri/tool/search/engines.rb
218
- - lib/pikuri/tool/search/exa.rb
219
- - lib/pikuri/tool/search/rate_limiter.rb
220
- - lib/pikuri/tool/search/result.rb
221
- - lib/pikuri/tool/skill.rb
222
- - lib/pikuri/tool/skill_catalog.rb
223
- - lib/pikuri/tool/sub_agent.rb
224
- - lib/pikuri/tool/web_scrape.rb
225
- - lib/pikuri/tool/web_search.rb
226
- - lib/pikuri/tool/workspace.rb
227
- - lib/pikuri/tool/write.rb
228
- - lib/pikuri/url_cache.rb
229
- - lib/pikuri/version.rb
230
- - prompts/coding-system-prompt.txt
231
- - prompts/pikuri-chat.txt
232
118
  homepage: https://codeberg.org/mvysny/pikuri
233
119
  licenses:
234
120
  - MIT
@@ -255,5 +141,5 @@ requirements: []
255
141
  rubygems_version: 3.5.22
256
142
  signing_key:
257
143
  specification_version: 4
258
- summary: A small, privacy-first Ruby toolkit for building local AI assistants.
144
+ summary: 'Convenience metagem: installs every pikuri-* gem.'
259
145
  test_files: []
data/CHANGELOG.md DELETED
@@ -1,62 +0,0 @@
1
- # Changelog
2
-
3
- All notable changes to pikuri are recorded here. Format follows
4
- [Keep a Changelog](https://keepachangelog.com/en/1.1.0/); the project
5
- uses semver as documented in `lib/pikuri/version.rb`.
6
-
7
- ## [Unreleased]
8
-
9
- ## [0.0.1] - 2026-05-14 — first packaged release
10
-
11
- The initial gem release. Pikuri is shipped as a **library** — there are
12
- no executables installed by `gem install pikuri`. The `bin/pikuri-chat`
13
- and `bin/pikuri-code` scripts in the source tree are dev/demo entry
14
- points; production binaries built on pikuri (notably the planned
15
- `pikuri-tui`) will live in their own downstream gems.
16
-
17
- ### Added
18
- - `pikuri.gemspec` with runtime deps pulled from the previous `Gemfile`
19
- (one source of truth; `Gemfile` now uses `gemspec`).
20
- - `Pikuri::VERSION` constant (`lib/pikuri/version.rb`); Zeitwerk is
21
- told to ignore the file since the constant is `VERSION`, not
22
- `Version`.
23
- - `LICENSE` (MIT) and gemspec license metadata.
24
- - `Pikuri::PROMPTS_DIR` and `Pikuri.prompt(name)` — downstream library
25
- users can read pikuri's bundled system prompts as a starting point
26
- for their own wiring.
27
- - `Tool::Bash` emits a loud warning at construction: the tool runs
28
- commands unsandboxed under pikuri's UID and can read `~/.ssh`, AWS
29
- credentials, etc. A future release will gate this behind a sandbox.
30
- - `Pikuri::Tool::SkillCatalog` + `Pikuri::Tool::Skill` — pikuri's
31
- implementation of the [Agent Skills standard](https://agentskills.io/specification).
32
- `SkillCatalog` discovers and validates `SKILL.md` files under the
33
- standard `.pikuri/skills`, `.claude/skills`, `.agents/skills`
34
- directories (precedence in that order); `Tool::Skill` is auto-
35
- registered by `Agent#initialize` whenever the wired-in catalog is
36
- non-empty, and the catalog's prompt block is appended to the system
37
- prompt so the LLM sees the available inventory without an extra
38
- round-trip.
39
- - `mise.toml` pinning Ruby 3.3, matching the gemspec floor.
40
- - `CHANGELOG.md` (this file).
41
-
42
- ### Changed
43
- - **Namespace move.** Top-level `Agent`, `Tool`, and `UrlCache` are now
44
- `Pikuri::Agent`, `Pikuri::Tool`, `Pikuri::UrlCache`. All bundled
45
- tools, listeners, and helpers live under `Pikuri::*`. Standard gem
46
- layout: `lib/pikuri.rb` + `lib/pikuri/**/*.rb`; `spec/` mirrors it.
47
- - `Pikuri::Agent::Listener::InMemoryList` renamed to `InMemoryMessageList`
48
- to clarify what it records (message events).
49
- - `UrlCache::ROOT_DIR` follows the XDG Base Directory spec:
50
- `$XDG_CACHE_HOME/pikuri/url_cache` if set, else
51
- `~/.cache/pikuri/url_cache`. Previously `/tmp/pikuri/cache`.
52
- - `bin/pikuri-chat` and `bin/pikuri-code` read prompts via
53
- `Pikuri.prompt(name)` instead of hand-rolled `__dir__` arithmetic.
54
-
55
- ### Project scope
56
- - Pikuri targets **Linux**; macOS may work; Windows is unsupported.
57
- Rationale: the eventual Bash-tool sandbox (Docker / bubblewrap) and
58
- the existing reliance on POSIX shell + GNU coreutils + XDG layout
59
- make a Windows port more cost than benefit.
60
- - Hard ceiling on source size: a privacy-conscious user should be able
61
- to read pikuri end-to-end in an evening and decide whether to trust
62
- it outside a sandbox. New features compete against that budget.
data/GETTING_STARTED.md DELETED
@@ -1,223 +0,0 @@
1
- # Getting started with pikuri-chat
2
-
3
- This guide walks you from a fresh checkout to a working privacy-first
4
- chatbot running entirely on your own machine. The assumed platform is
5
- Ubuntu (or another Debian-derived Linux); adapt the package commands if
6
- you're elsewhere.
7
-
8
- ## 1. Clone and install
9
-
10
- ```sh
11
- git clone https://codeberg.org/mvysny/pikuri.git
12
- cd pikuri
13
-
14
- # Ruby 3.x and Bundler. Pikuri has no Rails or native-extension
15
- # headaches — the stock distro packages are fine.
16
- sudo apt install ruby ruby-bundler
17
-
18
- bundle install
19
- ```
20
-
21
- That installs all the gems pikuri needs (`ruby_llm`, `faraday`,
22
- `nokogiri`, `tty-markdown`, …) into your user gem path.
23
-
24
- ## 2. Try to run pikuri-chat (and watch it fail)
25
-
26
- ```sh
27
- ./bin/pikuri-chat "Hello"
28
- ```
29
-
30
- You'll see a connection error. That's expected — pikuri-chat ships
31
- pointed at a local `llama.cpp` server, and you don't have one running
32
- yet. We'll start one in the next step.
33
-
34
- This is the privacy property in action: pikuri does not silently fall
35
- back to a cloud provider. No model means no answer.
36
-
37
- ## 3. Install llama.cpp
38
-
39
- `llama.cpp` is the project that actually runs the model. Ubuntu 24.04
40
- and newer have it packaged:
41
-
42
- ```sh
43
- sudo apt install llama.cpp
44
- ```
45
-
46
- This gives you `llama-server` on your `$PATH`. If your distro doesn't
47
- package it, follow the build instructions at
48
- <https://github.com/ggml-org/llama.cpp> — pikuri only needs the
49
- `llama-server` binary.
50
-
51
- ## 4. Start the model
52
-
53
- The model `bin/pikuri-chat` is wired for is `unsloth/Qwen3.6-35B-A3B-GGUF`
54
- — a mixture-of-experts model from the Qwen series, quantized by the
55
- folks at Unsloth so it fits in regular hardware. `llama-server` can
56
- download it from Hugging Face for you on first run:
57
-
58
- ```sh
59
- llama-server \
60
- -hf unsloth/Qwen3.6-35B-A3B-GGUF \
61
- --hf-file Qwen3.6-35B-A3B-UD-Q4_K_M.gguf \
62
- -c 65536 \
63
- --jinja
64
- ```
65
-
66
- What each flag does:
67
-
68
- - `-hf unsloth/Qwen3.6-35B-A3B-GGUF` — Hugging Face repo to pull from.
69
- - `--hf-file Qwen3.6-35B-A3B-UD-Q4_K_M.gguf` — pick the
70
- Q4_K_M quantization (good size/quality tradeoff).
71
- - `-c 65536` — 64K context window. Pikuri's agent loop accumulates
72
- tool observations into the context, so headroom matters.
73
- - `--jinja` — enable Jinja chat templates. The Qwen3 series needs this
74
- for correct tool-call formatting.
75
-
76
- **Expect this to be slow on CPU.** A 35B-parameter mixture-of-experts
77
- model running on CPU can manage a few tokens per second. If you have
78
- an NVIDIA or AMD GPU with enough VRAM, add `-ngl 99` to offload all
79
- layers onto the GPU — this is the single biggest speedup you can get.
80
- See `llama-server --help` and the
81
- [llama.cpp docs](https://github.com/ggml-org/llama.cpp/tree/master/tools/server)
82
- for tuning options (`-t` for thread count, `-ngl N` for partial GPU
83
- offload, `--mlock`, and friends).
84
-
85
- The server binds to `127.0.0.1:8080` by default, and `bin/pikuri-chat`
86
- is wired to `http://localhost:8080/v1` — so if you're running both on
87
- the same machine, no further configuration is needed. If your
88
- `llama-server` lives on another host, edit the `openai_api_base`
89
- string near the top of `bin/pikuri-chat` to match.
90
-
91
- ## 5. Talk to it
92
-
93
- In a second terminal, leaving `llama-server` running:
94
-
95
- ```sh
96
- ./bin/pikuri-chat
97
- ```
98
-
99
- You'll get a `>` prompt. Try something the model can't answer from
100
- memory alone — that's where the tools come in:
101
-
102
- ```
103
- > What is 1837 * 4291, and what's the current Ruby stable version?
104
- ```
105
-
106
- You should see the model emit reasoning, call the `calculator` tool
107
- for the multiplication, call `web_search` (and likely `web_scrape`)
108
- for the Ruby version, then reply in plain text. Use Ctrl+D or Ctrl+C
109
- to exit.
110
-
111
- ## How the agentic loop works (and why it's private)
112
-
113
- Pikuri runs the standard *Thought → Tool-call → Observation* loop:
114
-
115
- 1. The model receives your message plus the running conversation.
116
- 2. It produces either a final answer (and the turn ends) or a tool
117
- call — a structured request like *"call `web_search` with query
118
- `…`"*.
119
- 3. Pikuri executes the requested tool locally, capturing its output as
120
- an *observation*.
121
- 4. The observation is appended to the conversation and the model is
122
- called again.
123
-
124
- The model itself runs entirely inside your `llama-server` process. It
125
- has **no network access** of its own — it can only reason and emit
126
- text. The single way information leaves your machine is when the model
127
- asks pikuri to call a network-touching tool, and pikuri actually
128
- performs that call on your behalf. If you never give the model network
129
- tools, nothing the model "thinks about" can ever leave the box.
130
-
131
- This is meaningfully stronger than the typical hosted-assistant
132
- arrangement: there is no provider receiving your prompts, no telemetry
133
- pipeline, and no fine-tuning corpus being assembled from your chats.
134
-
135
- If you'd like to *see* this loop implemented in a handful of files
136
- with nothing else in the way, the sister project
137
- [agentic-loop-demo](https://codeberg.org/mvysny/agentic-loop-demo) is
138
- written exactly for that. Pikuri uses the same shape, just wrapped in
139
- tools, listeners, and sub-agents.
140
-
141
- ## What tools `bin/pikuri-chat` ships with
142
-
143
- Four tools, all defined in `lib/pikuri/tool/` and wired in `bin/pikuri-chat`:
144
-
145
- - **`calculator`** — evaluates an arithmetic expression with Dentaku.
146
- Local, no network.
147
- - **`web_search`** — runs a search query through one of the configured
148
- search providers and returns a Markdown list of titles, URLs, and
149
- snippets. See below for the privacy posture of each provider.
150
- - **`web_scrape`** — fetches an HTML page or PDF, strips the chrome
151
- with readability extraction, and returns the main content as
152
- Markdown. The model typically chains `web_search` → pick a URL →
153
- `web_scrape` to read the full article.
154
- - **`fetch`** — downloads a URL verbatim (JSON, CSV, robots.txt,
155
- source files) without any rendering pass that would corrupt the
156
- bytes.
157
-
158
- Plus a built-in *sub-agent* facility (enabled by
159
- `agent.allow_sub_agent`): the model can dispatch a focused side-quest
160
- to a fresh agent so the noisy intermediate observations don't pollute
161
- the main context.
162
-
163
- ## Search providers and their privacy trade-offs
164
-
165
- `web_search` is a cascade across whichever providers you have
166
- configured. The orchestration lives in `lib/pikuri/tool/search/engines.rb`;
167
- each provider's privacy posture is documented in detail at the top of
168
- its source file.
169
-
170
- ### DuckDuckGo (default, no setup)
171
-
172
- Always available — no API key, no registration. Pikuri scrapes the
173
- public HTML endpoint at `html.duckduckgo.com`. DuckDuckGo's policy is
174
- that they don't save your IP alongside searches, don't sell personal
175
- information, and proxy the request so downstream content providers
176
- can't profile you. The catch: DDG is largely a relay over Bing for
177
- web results, so the *query content* still reaches Microsoft for
178
- fulfillment, even though identifying info is stripped on the way out.
179
-
180
- Good enough for everyday curiosity. See
181
- `lib/pikuri/tool/search/duckduckgo.rb` for the full write-up.
182
-
183
- ### Brave Search API (recommended for sensitive queries)
184
-
185
- The best privacy posture of the three. Brave does **not** train its
186
- models on your queries, does not link queries to identifiers, and
187
- retains query logs for 90 days by default (Zero Data Retention is
188
- available on their Enterprise plan).
189
-
190
- To enable it, register for a free API key at
191
- <https://api-dashboard.search.brave.com> — the "Data for Search" tier
192
- gives you 1 query/sec and ~2k queries/month at no cost. Then export
193
- the key before starting pikuri:
194
-
195
- ```sh
196
- export BRAVE_SEARCH_API_KEY=your-key-here
197
- ./bin/pikuri-chat
198
- ```
199
-
200
- Once the env var is set, Brave joins the cascade and may be chosen
201
- over DuckDuckGo for any given query. See `lib/pikuri/tool/search/brave.rb`.
202
-
203
- ### Exa (paid, weakest privacy)
204
-
205
- Optional. Exa is a paid neural-search API; activate it by setting
206
- `EXA_API_KEY`. Be aware that Exa's Terms grant them a
207
- *perpetual, irrevocable, sub-licensable* license over the queries you
208
- submit, and their privacy policy explicitly says queries are used for
209
- training. Don't enable Exa if your search history would be
210
- embarrassing or sensitive in a training set.
211
-
212
- See `lib/pikuri/tool/search/exa.rb` for the full privacy posture.
213
-
214
- ### Recommended setup for best privacy
215
-
216
- 1. Run `llama-server` locally (Step 4 above).
217
- 2. Register a free Brave Search API key and `export
218
- BRAVE_SEARCH_API_KEY=…`.
219
- 3. Leave Exa unset.
220
-
221
- With this configuration, your prompts never leave your machine, and
222
- your search queries hit Brave under a clear no-training-on-queries
223
- commitment.
data/LICENSE DELETED
@@ -1,21 +0,0 @@
1
- The MIT License (MIT)
2
-
3
- Copyright (c) 2026 Martin Vysny
4
-
5
- Permission is hereby granted, free of charge, to any person obtaining a copy
6
- of this software and associated documentation files (the "Software"), to deal
7
- in the Software without restriction, including without limitation the rights
8
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
- copies of the Software, and to permit persons to whom the Software is
10
- furnished to do so, subject to the following conditions:
11
-
12
- The above copyright notice and this permission notice shall be included in
13
- all copies or substantial portions of the Software.
14
-
15
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
- THE SOFTWARE.
@@ -1,41 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Pikuri
4
- class Agent
5
- # The trio of arguments that has to travel together to +RubyLLM.chat+
6
- # for model resolution to come out the same on every construction:
7
- # the model id, the provider hint, and the registry-bypass flag.
8
- #
9
- # Bundling them is structural protection against a recurring bug
10
- # class — every forwarding site (the synthesizer rescue in
11
- # {Agent#run_loop}, {Tool::SubAgent} spawning a sub-agent) used to
12
- # pass the three individually, and dropping one routed the spawned
13
- # chat to a different server or raised +RubyLLM::ModelNotFoundError+
14
- # on the unknown model id. With a single value object the call site
15
- # can't silently miss a field.
16
- #
17
- # Pure data carrier: no +RubyLLM+ references here, so the seam stays
18
- # in {Agent}, +bin/pikuri-chat+, and {Tool}.
19
- #
20
- # @!attribute [r] model
21
- # @return [String, nil] LLM identifier; +nil+ defers to
22
- # +RubyLLM.config.default_model+ at {Agent} construction time
23
- # @!attribute [r] provider
24
- # @return [Symbol, nil] forwarded to +RubyLLM.chat+. Required
25
- # together with +assume_model_exists+ when pointing at a local
26
- # OpenAI-compatible server (llama.cpp, gpustack, ...) whose model
27
- # ids are not in ruby_llm's bundled registry.
28
- # @!attribute [r] assume_model_exists
29
- # @return [Boolean] forwarded to +RubyLLM.chat+; +true+ skips
30
- # ruby_llm's registry lookup and trusts the supplied model id.
31
- # Requires +provider+.
32
- class ChatTransport < Data.define(:model, :provider, :assume_model_exists)
33
- # @param model [String, nil]
34
- # @param provider [Symbol, nil]
35
- # @param assume_model_exists [Boolean]
36
- def initialize(model:, provider: nil, assume_model_exists: false)
37
- super
38
- end
39
- end
40
- end
41
- end