pikuri 0.0.1 → 0.0.4

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 +43 -179
  3. data/lib/pikuri.rb +16 -162
  4. metadata +66 -123
  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
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 6ce82e87d9498175b524fae4b97d8409758d8fe18783bd7084ae79afd606c56a
4
- data.tar.gz: a17444b138a83252172ba0bcaa9d99129642cef0be2e1307bcc0b9203092ebb8
3
+ metadata.gz: 8738b90aabdb724518baa950866de9b8719a6e45e53580662bf4926e16bdbd60
4
+ data.tar.gz: 1df5f75e1290b1c390a6cd858ce9d0d45062299a9a6a0624598e99bdea47e77c
5
5
  SHA512:
6
- metadata.gz: 5620bfd3290ea12b6069375382c1e79e769a7a2822d94b91bc166c2d0ac50ea41a2b75fd618ff006ac4500398da05ab9d0f970b123e44ef2a4c6f01e1096dd4d
7
- data.tar.gz: 995b317bce1952d161c2c4e0088eb92ee9cf7788252c7496949d14633e9126acfc4cedfb7a5f105f9ab4a6e359d63b41cce5d3246cc113d334c07ab259218862
6
+ metadata.gz: fc0724357798692147811c9f138c73feb8081125bf1d3462ad1ba8463894fa7acd236c3813782fc8e96f899d0e8e3edda6db7edc10f252c07213c0b5bad58d7d
7
+ data.tar.gz: 9feaf1d95c74c0cee37c22e18b8771321870d8ab3c6efb4fd06262f7fd51d013f842c44c0272c6c14c20b6fc71047d1d3bfe80fbbb9102df11e0b4039bc2eb6c
data/README.md CHANGED
@@ -1,193 +1,57 @@
1
- # pikuri
1
+ # pikuri (metagem)
2
2
 
3
- A small Ruby AI assistant you run on your own machine. `bin/pikuri-chat`
4
- is a general-purpose chatbot with a calculator, web search, web
5
- scraping, and a fetch tool wired by default to a
6
- [llama.cpp](https://github.com/ggml-org/llama.cpp) server running
7
- locally, so the conversation never leaves your computer unless the
8
- model itself decides to call a tool.
3
+ The convenience bundle for the
4
+ [pikuri](https://codeberg.org/mvysny/pikuri) AI-assistant toolkit:
5
+ `gem install pikuri` brings in every pikuri-* gem in one shot, and
6
+ `require 'pikuri'` boots them all.
9
7
 
10
- ## Quick start
8
+ This gem ships no Ruby code of its own — its `lib/pikuri.rb` is
9
+ seven `require` lines, one per sibling.
11
10
 
12
- ```sh
13
- git clone https://codeberg.org/mvysny/pikuri.git
14
- cd pikuri
15
-
16
- # Ruby 3.x + bundler (Ubuntu/Debian)
17
- sudo apt install ruby ruby-bundler
18
-
19
- bundle install
20
-
21
- ./bin/pikuri-chat "What is 17 * 23?"
22
- ```
23
-
24
- The first run won't get far — pikuri-chat needs a model behind it. See
25
- [GETTING_STARTED.md](GETTING_STARTED.md) for the full walkthrough:
26
- installing `llama.cpp`, pulling a model, starting `llama-server`, and
27
- asking your first question.
28
-
29
- ## Using pikuri as a library
30
-
31
- Pikuri is shipped as a Ruby gem you can use in your own project. The
32
- recommended path: **first** play with `bin/pikuri-chat`, inspect the
33
- sources, get a feel for the shape — *then* pull pikuri into your
34
- project as a library:
11
+ ## Install
35
12
 
36
13
  ```ruby
37
- # In your Gemfile
14
+ # Gemfile
38
15
  gem 'pikuri'
39
16
  ```
40
17
 
41
- A minimal wiring — single agent, default `llama.cpp` transport, the
42
- bundled calculator + web-search tools, the same system prompt
43
- `pikuri-chat` uses:
44
-
45
- ```ruby
46
- require 'pikuri'
47
-
48
- RubyLLM.configure do |c|
49
- c.openai_api_base = 'http://localhost:8080/v1' # llama.cpp default
50
- c.openai_api_key = 'not-needed'
51
- end
52
-
53
- agent = Pikuri::Agent.new(
54
- transport: Pikuri::Agent::ChatTransport.new(
55
- model: 'unsloth/Qwen3.6-35B-A3B-GGUF',
56
- provider: :openai,
57
- assume_model_exists: true
58
- ),
59
- system_prompt: Pikuri.prompt(:'pikuri-chat'),
60
- tools: [Pikuri::Tool::CALCULATOR, Pikuri::Tool::WEB_SEARCH],
61
- listeners: Pikuri::Agent::ListenerList.new([
62
- Pikuri::Agent::Listener::Terminal.new,
63
- Pikuri::Agent::Listener::StepLimit.new(max: 20)
64
- ])
65
- )
66
-
67
- agent.run_loop(user_message: 'What is 17 * 23?')
68
- ```
69
-
70
- `bin/pikuri-chat` and `bin/pikuri-code` in this repo are the canonical
71
- working examples — they're dev/demo scripts (not installed by
72
- `gem install pikuri`), but they're the easiest place to crib wiring
73
- from. The bundled system prompts under `prompts/` are loadable as a
74
- starting point via `Pikuri.prompt(name)`.
75
-
76
- ## Why this exists
77
-
78
- The existing self-hosted agent stacks have grown big and now have a
79
- steep learning curve — a privacy-conscious user arriving fresh hits a
80
- wall of JSON configuration before the first conversation. Pikuri is
81
- the deliberate counter-move:
82
-
83
- - **Privacy-first.** Defaults wire a local `llama.cpp` server. No
84
- cloud account, no API key, no telemetry, no request leaving the
85
- machine — unless you explicitly opt in by configuring an external
86
- provider, or the model calls a network tool like `web_search`.
87
- - **Simple.** Two short scripts, sane defaults, no config file required
88
- to get the first conversation going.
89
- - **Gentle learning curve.** Defaults work without a config file. The
90
- surface area grows as you grow into it: start by chatting, then add
91
- a search API key when you want better results, then edit the system
92
- prompt when you want to specialise behaviour.
93
- - **Teaches you how to use it.** [GETTING_STARTED.md](GETTING_STARTED.md)
94
- walks you from zero — a fresh checkout, no model running — to a
95
- working personal assistant: installing the local model server,
96
- asking your first question, understanding what each bundled tool
97
- does, and choosing a search backend that matches your privacy
98
- comfort level.
18
+ Transitively installs:
19
+ - [`pikuri-core`](../pikuri-core/README.md) the foundation
20
+ - [`pikuri-skills`](../pikuri-skills/README.md) — Agent Skills support
21
+ - [`pikuri-workspace`](../pikuri-workspace/README.md) — filesystem tools
22
+ - [`pikuri-code`](../pikuri-code/README.md) — Bash + `bin/pikuri-code`
23
+ - [`pikuri-mcp`](../pikuri-mcp/README.md) — MCP support
24
+ - [`pikuri-subagents`](../pikuri-subagents/README.md) — `agent` tool + bundled personas + `bin/pikuri-minions`
25
+ - [`pikuri-assistant`](../pikuri-assistant/README.md) `bin/pikuri-assistant`
99
26
 
100
- ## Curious how the agentic loop actually works?
27
+ All version-locked together — bumping the metagem requires the
28
+ matching sibling versions.
101
29
 
102
- Pikuri sits on top of [ruby_llm](https://rubyllm.com), which owns the
103
- Thought → Tool-call → Observation loop. If you want to *learn* how
104
- that loop works internally — minimal code, no extension surface,
105
- nothing to wade through — read
106
- [agentic-loop-demo](https://codeberg.org/mvysny/agentic-loop-demo).
107
- It's the same author's small didactic project, written precisely so
108
- the source is the lesson. Pikuri is the production-shaped sibling:
109
- same loop, plus tools, listeners, sub-agents, and ergonomics.
30
+ ## When NOT to use this gem
110
31
 
111
- # More Substance
32
+ Privacy-conscious users who care about a minimal dependency tree
33
+ should install just the lean core + the extensions they actually
34
+ need:
112
35
 
113
- pikuri-chat builds your understanding of pikuri underpinnings, but it's just a toy.
114
- The real fun begins now.
115
-
116
- ## pikuri-code
117
-
118
- An in-repo coding agent in the spirit of Claude Code, opencode, or
119
- pi-code — but kept deliberately small so you can read the sources in
120
- an evening. Wire-by-wire it's the same `Pikuri::Agent` as
121
- `pikuri-chat`, with a different system prompt and a different toolset:
122
- `read`, `write`, `edit`, `grep`, `glob`, `bash`, plus the web tools
123
- and the calculator. Sub-agents are enabled, and any
124
- [Agent Skills](https://agentskills.io/specification) discovered under
125
- `.pikuri/skills`, `.claude/skills`, `.agents/skills` (project or home)
126
- get exposed to the model on demand.
127
-
128
- Run it from the root of the repo you want it to work in:
129
-
130
- ```sh
131
- cd ~/code/your-project
132
- /path/to/pikuri/bin/pikuri-code
133
- ```
134
-
135
- You'll land in a REPL — type a request at the `>` prompt, hit enter,
136
- and the agent will start reading files, running commands, and editing
137
- code to satisfy it. Ctrl+D (or Ctrl+C) exits. You can also pass an
138
- initial message on the command line:
139
-
140
- ```sh
141
- /path/to/pikuri/bin/pikuri-code "find the failing spec and fix it"
36
+ ```ruby
37
+ gem 'pikuri-core'
38
+ gem 'pikuri-mcp' # if they want MCP
39
+ gem 'pikuri-skills' # if they want skills
40
+ # ... etc.
142
41
  ```
143
42
 
144
- The first time the agent wants to write a file or run a shell command,
145
- it prompts you on the terminal (`(y/n)?`). Read what it's about to do
146
- before you say yes. If an `AGENTS.md` or `CLAUDE.md` exists at the
147
- workspace root, it's prepended to the system prompt as project
148
- context.
149
-
150
- ### Security: this is a tech demo, treat it accordingly
151
-
152
- **Do not run `pikuri-code` against a sensitive checkout on a machine
153
- that holds secrets you care about.** It is a working demo of the
154
- coding-agent shape, *not* a hardened tool. The threat model has
155
- glaring holes:
156
-
157
- - **No sandbox.** The `bash` tool runs commands as your user, with
158
- your environment, your `$HOME`, your `~/.ssh`, your shell history,
159
- your browser cookies, your cloud CLI credentials — all reachable.
160
- An LLM that's been prompt-injected (e.g. by a malicious README it
161
- scraped, a poisoned dependency, or a crafted file in the repo) can
162
- ask to run `cat ~/.ssh/id_ed25519 | curl -X POST ...` and the only
163
- thing standing between that and exfiltration is *you* reading the
164
- confirmation prompt carefully. The workspace lock applies to
165
- pikuri's own `read`/`write`/`edit`/`grep`/`glob` tools — it does
166
- **not** apply to `bash`, which can `cat`, `cp`, `scp`, `curl`
167
- anything the OS lets your user touch.
168
- - **`--yolo` auto-approves everything.** That flag exists for use
169
- *inside* a disposable container or VM. Running `--yolo` on your
170
- laptop is equivalent to handing the model a root shell. Don't.
171
- - **Network tools fetch arbitrary URLs.** `web_search`, `web_scrape`,
172
- and `fetch` are happy to pull whatever the model asks for, and the
173
- content of those pages then becomes part of the conversation —
174
- classic indirect prompt-injection surface.
175
- - **No audit log of approved actions.** Once you approve a `bash`
176
- command it runs; there's no separate record beyond your scrollback.
177
-
178
- In short: run it inside a Docker container, a dev container, a VM, a
179
- fresh user account — anywhere you'd be fine with a stranger having a
180
- shell. The sandboxing story is a known gap and tracked as future
181
- work (see `IDEAS.md`); until it lands, **assume the agent can do
182
- anything your user can do**, and approve prompts on that basis.
183
-
184
- ## pikuri-assistant
185
-
186
- Has access to your private documents, can read and respond to e-mails, remembers
187
- stuff. TODO implemented in the future.
188
-
189
- ## Tests
190
-
191
- ```sh
192
- bundle exec rspec
193
- ```
43
+ `pikuri-core` is the minimal install. Adding `pikuri-mcp` adds
44
+ exactly one new runtime gem (`mcp`); `pikuri-workspace` /
45
+ `pikuri-skills` / `pikuri-code` / `pikuri-subagents` /
46
+ `pikuri-assistant` add nothing beyond pikuri's own gems. The dep
47
+ tree stays auditable.
48
+
49
+ ## Further reading
50
+
51
+ - **Narrative walkthrough:** the [pikuri
52
+ guide](../docs/guide/) a short sequential book covering the
53
+ whole family, chapter by chapter.
54
+ - **API reference:** browse the YARD docs at
55
+ <https://rubydoc.info/gems/pikuri> (once published), or run
56
+ `bundle exec yard` in any sibling gem's directory for a local
57
+ copy of that gem's docs.
data/lib/pikuri.rb CHANGED
@@ -1,165 +1,19 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'logger'
4
- require 'zeitwerk'
5
-
6
- # +Pikuri::VERSION+ lives in its own tiny file so the gemspec can read
7
- # the version constant via +require_relative+ at build time without
8
- # loading Zeitwerk and every runtime dep. Requiring it here makes the
9
- # constant available to ordinary +require 'pikuri'+ callers too —
10
- # without this line, Zeitwerk's ignore-rule below would leave
11
- # +Pikuri::VERSION+ undefined for anyone using the installed gem.
12
- require_relative 'pikuri/version'
13
-
14
- # Boot file: configures the Zeitwerk autoloader for every file under
15
- # +lib/pikuri/+ and eager-loads them all. After +require 'pikuri'+,
16
- # every constant pikuri ships (+Pikuri::Agent+, +Pikuri::Tool+,
17
- # +Pikuri::Tool::Calculator+, +Pikuri::Tool::Scraper::HTML+, ...) is
18
- # defined and resolvable.
19
- #
20
- # Beyond loading, the +Pikuri+ module owns the logging surface — see
21
- # {.logger_for}, {.log_io=}, and the +PIKURI_LOG+ /
22
- # +PIKURI_LOG_<NAME>+ env vars. Each subsystem holds its own
23
- # memoized +Logger+, all writing through a shared IO that
24
- # {.log_io=} can swap in one shot (handy in tests, daemons, or
25
- # anywhere stderr isn't the right sink).
3
+ # +pikuri+ metagem entry file. Boots every sibling gem in dependency
4
+ # order so +require 'pikuri'+ pulls in the whole pikuri-* family in
5
+ # one shot. Each sibling owns its own Zeitwerk loader + PROMPT_DIRS
6
+ # registration; we just need them loaded.
26
7
  #
27
- # == Why eager-load
28
- #
29
- # Tool implementations (+Pikuri::Tool::CALCULATOR+,
30
- # +Pikuri::Tool::WEB_SEARCH+, +Pikuri::Tool::WEB_SCRAPE+,
31
- # +Pikuri::Tool::FETCH+) are +ALL_CAPS+ value constants rather than
32
- # classes/modules, and Zeitwerk only auto-loads constants that match
33
- # its filename-↔-CamelCase convention. Eager-loading at boot guarantees
34
- # the files defining those values run, so the bin script can splat them
35
- # straight into +Pikuri::Agent.new(tools: [...])+ without per-file
36
- # +require+ ceremony. The cost is a few milliseconds of startup —
37
- # negligible compared to a single LLM round-trip.
38
- module Pikuri
39
- # Absolute path to the directory holding pikuri's bundled system
40
- # prompts (+pikuri-chat.txt+, +coding-system-prompt.txt+). Resolves
41
- # correctly both in a source checkout and in an installed gem because
42
- # +__dir__+ tracks the file's actual location either way; the gem
43
- # ships +prompts/+ as a sibling of +lib/+ so the same relative jump
44
- # works.
45
- #
46
- # Exposed publicly so a downstream library user can read pikuri's
47
- # prompts as a starting point for their own system prompt (or use
48
- # them verbatim). Prefer {.prompt} for the common case of loading
49
- # one by name; reach for this constant only if you need the
50
- # directory itself (e.g. to list available prompts).
51
- #
52
- # @return [String]
53
- PROMPTS_DIR = File.expand_path('../prompts', __dir__)
54
-
55
- # Mapping from +PIKURI_LOG+ env-var values (lowercased) to
56
- # {Logger} level constants. Anything else falls back to +INFO+.
57
- #
58
- # @return [Hash{String=>Integer}]
59
- LOG_LEVELS = {
60
- 'debug' => Logger::DEBUG,
61
- 'info' => Logger::INFO,
62
- 'warn' => Logger::WARN,
63
- 'error' => Logger::ERROR,
64
- 'fatal' => Logger::FATAL
65
- }.freeze
66
-
67
- @log_io = $stderr
68
- @log_loggers = {} # name → Logger; lets {.log_io=} rewire all of them
69
- @log_default = LOG_LEVELS.fetch(ENV['PIKURI_LOG'].to_s.downcase, Logger::INFO)
70
-
71
- class << self
72
- # @return [IO] shared sink every {.logger_for} writes through
73
- attr_reader :log_io
74
-
75
- # Swap the shared sink (e.g. a +StringIO+ in tests, a file in a
76
- # daemon). Re-points every logger already handed out by
77
- # {.logger_for} so callers don't have to re-fetch them.
78
- #
79
- # Why we don't use +Logger#reopen+: that method closes the previous
80
- # sink before installing the new one, which makes "swap to a
81
- # capture +StringIO+, then swap back to the original" impossible —
82
- # the original handle would be dead the second time around. Instead
83
- # we swap each logger's +@logdev+ to a fresh +Logger::LogDevice+
84
- # over the new +io+, leaving the previous device untouched so the
85
- # caller can hand the same +IO+ back in later. This uses a documented
86
- # but internal Logger ivar; if a future Ruby renames it the
87
- # +Engines+ logging specs will fail loudly.
88
- #
89
- # @param io [IO] new sink for every Pikuri logger
90
- # @return [IO]
91
- def log_io=(io)
92
- @log_io = io
93
- @log_loggers.each_value do |lg|
94
- lg.instance_variable_set(:@logdev, Logger::LogDevice.new(io))
95
- end
96
- io
97
- end
98
-
99
- # Memoized {Logger} tagged with +name+ in its +progname+, so each
100
- # subsystem's lines stand out in the shared sink. Level resolves
101
- # in this order: +PIKURI_LOG_<NAME>+ (e.g. +PIKURI_LOG_ENGINES=debug+),
102
- # then +PIKURI_LOG+, then +INFO+.
103
- #
104
- # Repeated calls with the same +name+ return the same instance so
105
- # there is one logger per subsystem and {.log_io=} can rewire them
106
- # all in one shot.
107
- #
108
- # @param name [String] subsystem tag (rendered as +progname+)
109
- # @return [Logger]
110
- def logger_for(name)
111
- @log_loggers[name] ||= begin
112
- lg = Logger.new(@log_io, progname: name)
113
- override = ENV["PIKURI_LOG_#{name.upcase}"].to_s.downcase
114
- lg.level = LOG_LEVELS.fetch(override, @log_default)
115
- lg
116
- end
117
- end
118
-
119
- # Read a bundled prompt by basename. +name+ is matched against the
120
- # files in {PROMPTS_DIR}; a +.txt+ extension is auto-appended if
121
- # absent. Symbols are accepted as a convenience (+:pikuri-chat+ /
122
- # +'pikuri-chat'+ / +'pikuri-chat.txt'+ all resolve to the same file).
123
- #
124
- # Intended for downstream library users who want to bootstrap their
125
- # own +Pikuri::Agent+ wiring from pikuri's defaults — read the
126
- # prompt, customize the bits they care about, hand the result to
127
- # +Agent.new(system_prompt: ...)+.
128
- #
129
- # @example
130
- # chat_prompt = Pikuri.prompt(:'pikuri-chat')
131
- # agent = Pikuri::Agent.new(system_prompt: chat_prompt, ...)
132
- #
133
- # @param name [String, Symbol] basename of the prompt file
134
- # @return [String] file contents
135
- # @raise [ArgumentError] if no matching file exists in {PROMPTS_DIR}
136
- def prompt(name)
137
- basename = name.to_s
138
- basename += '.txt' unless basename.end_with?('.txt')
139
- path = File.join(PROMPTS_DIR, basename)
140
- unless File.exist?(path)
141
- available = Dir.children(PROMPTS_DIR).sort.join(', ')
142
- raise ArgumentError, "Unknown pikuri prompt #{name.inspect}; available: #{available}"
143
- end
144
- File.read(path)
145
- end
146
- end
147
-
148
- Loader = Zeitwerk::Loader.new
149
- Loader.tag = 'pikuri'
150
- Loader.push_dir(File.expand_path('.', __dir__))
151
- Loader.ignore(__FILE__)
152
- # +lib/pikuri/version.rb+ defines +Pikuri::VERSION+ (an ALL_CAPS value
153
- # constant), not +Pikuri::Version+ as Zeitwerk would expect from the
154
- # filename — so tell the loader to skip it. The file is +require_relative+'d
155
- # at the top of this file (and also by the gemspec at build time), so
156
- # the constant is defined before Zeitwerk runs.
157
- Loader.ignore(File.expand_path('pikuri/version.rb', __dir__))
158
- Loader.inflector.inflect(
159
- 'html' => 'HTML',
160
- 'pdf' => 'PDF',
161
- 'duckduckgo' => 'DuckDuckGo'
162
- )
163
- Loader.setup
164
- Loader.eager_load
165
- end
8
+ # Privacy-conscious users who want a minimal dependency tree should
9
+ # install +pikuri-core+ directly and skip this metagem.
10
+ require 'pikuri-core'
11
+ require 'pikuri-skills'
12
+ require 'pikuri-tasks'
13
+ require 'pikuri-memory'
14
+ require 'pikuri-workspace'
15
+ require 'pikuri-mcp'
16
+ require 'pikuri-code'
17
+ require 'pikuri-subagents'
18
+ require 'pikuri-vectordb'
19
+ require 'pikuri-assistant'