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.
- checksums.yaml +4 -4
- data/README.md +31 -179
- data/lib/pikuri.rb +12 -162
- metadata +45 -159
- data/CHANGELOG.md +0 -62
- data/GETTING_STARTED.md +0 -223
- data/LICENSE +0 -21
- data/lib/pikuri/agent/chat_transport.rb +0 -41
- data/lib/pikuri/agent/context_window_detector.rb +0 -101
- data/lib/pikuri/agent/listener/in_memory_message_list.rb +0 -33
- data/lib/pikuri/agent/listener/message_listener.rb +0 -93
- data/lib/pikuri/agent/listener/step_limit.rb +0 -97
- data/lib/pikuri/agent/listener/terminal.rb +0 -137
- data/lib/pikuri/agent/listener/token_log.rb +0 -166
- data/lib/pikuri/agent/listener_list.rb +0 -113
- data/lib/pikuri/agent/message.rb +0 -61
- data/lib/pikuri/agent/synthesizer.rb +0 -120
- data/lib/pikuri/agent/tokens.rb +0 -56
- data/lib/pikuri/agent.rb +0 -286
- data/lib/pikuri/subprocess.rb +0 -166
- data/lib/pikuri/tool/bash.rb +0 -272
- data/lib/pikuri/tool/calculator.rb +0 -82
- data/lib/pikuri/tool/confirmer.rb +0 -96
- data/lib/pikuri/tool/edit.rb +0 -196
- data/lib/pikuri/tool/fetch.rb +0 -167
- data/lib/pikuri/tool/glob.rb +0 -310
- data/lib/pikuri/tool/grep.rb +0 -338
- data/lib/pikuri/tool/parameters.rb +0 -314
- data/lib/pikuri/tool/read.rb +0 -254
- data/lib/pikuri/tool/scraper/fetch_error.rb +0 -16
- data/lib/pikuri/tool/scraper/html.rb +0 -285
- data/lib/pikuri/tool/scraper/pdf.rb +0 -54
- data/lib/pikuri/tool/scraper/simple.rb +0 -177
- data/lib/pikuri/tool/search/brave.rb +0 -184
- data/lib/pikuri/tool/search/duckduckgo.rb +0 -196
- data/lib/pikuri/tool/search/engines.rb +0 -154
- data/lib/pikuri/tool/search/exa.rb +0 -217
- data/lib/pikuri/tool/search/rate_limiter.rb +0 -92
- data/lib/pikuri/tool/search/result.rb +0 -29
- data/lib/pikuri/tool/skill.rb +0 -80
- data/lib/pikuri/tool/skill_catalog.rb +0 -376
- data/lib/pikuri/tool/sub_agent.rb +0 -102
- data/lib/pikuri/tool/web_scrape.rb +0 -117
- data/lib/pikuri/tool/web_search.rb +0 -38
- data/lib/pikuri/tool/workspace.rb +0 -150
- data/lib/pikuri/tool/write.rb +0 -170
- data/lib/pikuri/tool.rb +0 -118
- data/lib/pikuri/url_cache.rb +0 -106
- data/lib/pikuri/version.rb +0 -10
- data/prompts/coding-system-prompt.txt +0 -28
- 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.
|
|
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-
|
|
11
|
+
date: 2026-05-22 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
|
-
name:
|
|
14
|
+
name: pikuri-assistant
|
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
|
16
16
|
requirements:
|
|
17
|
-
- -
|
|
17
|
+
- - '='
|
|
18
18
|
- !ruby/object:Gem::Version
|
|
19
|
-
version:
|
|
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:
|
|
26
|
+
version: 0.0.3
|
|
27
27
|
- !ruby/object:Gem::Dependency
|
|
28
|
-
name:
|
|
28
|
+
name: pikuri-code
|
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
|
30
30
|
requirements:
|
|
31
|
-
- -
|
|
31
|
+
- - '='
|
|
32
32
|
- !ruby/object:Gem::Version
|
|
33
|
-
version:
|
|
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:
|
|
40
|
+
version: 0.0.3
|
|
41
41
|
- !ruby/object:Gem::Dependency
|
|
42
|
-
name:
|
|
42
|
+
name: pikuri-core
|
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
|
44
44
|
requirements:
|
|
45
|
-
- -
|
|
45
|
+
- - '='
|
|
46
46
|
- !ruby/object:Gem::Version
|
|
47
|
-
version:
|
|
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:
|
|
54
|
+
version: 0.0.3
|
|
55
55
|
- !ruby/object:Gem::Dependency
|
|
56
|
-
name:
|
|
56
|
+
name: pikuri-mcp
|
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
|
58
58
|
requirements:
|
|
59
|
-
- -
|
|
59
|
+
- - '='
|
|
60
60
|
- !ruby/object:Gem::Version
|
|
61
|
-
version:
|
|
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:
|
|
68
|
+
version: 0.0.3
|
|
69
69
|
- !ruby/object:Gem::Dependency
|
|
70
|
-
name:
|
|
70
|
+
name: pikuri-skills
|
|
71
71
|
requirement: !ruby/object:Gem::Requirement
|
|
72
72
|
requirements:
|
|
73
|
-
- -
|
|
73
|
+
- - '='
|
|
74
74
|
- !ruby/object:Gem::Version
|
|
75
|
-
version:
|
|
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:
|
|
82
|
+
version: 0.0.3
|
|
83
83
|
- !ruby/object:Gem::Dependency
|
|
84
|
-
name:
|
|
84
|
+
name: pikuri-workspace
|
|
85
85
|
requirement: !ruby/object:Gem::Requirement
|
|
86
86
|
requirements:
|
|
87
|
-
- -
|
|
87
|
+
- - '='
|
|
88
88
|
- !ruby/object:Gem::Version
|
|
89
|
-
version:
|
|
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:
|
|
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
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
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:
|
|
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
|