Commit 8c04804

mo khan <mo@mokhan.ca>
2026-02-02 06:21:07
docs: add getting started docs
1 parent fd45e13
docs/modes/build.md
@@ -0,0 +1,93 @@
+# ELELEM-MODE-BUILD(7)
+
+## NAME
+
+elelem-mode-build - implementation with TDD
+
+## SYNOPSIS
+
+```
+/mode build
+```
+
+## DESCRIPTION
+
+Build mode is the primary implementation mode. The agent works through tasks
+from a story using test-driven development: write a failing test, implement
+minimal code to pass, then refactor.
+
+## ROLE
+
+- Work through Tasks in the specified story
+- Check off completed tasks
+- Follow TDD: write failing test, implement, refactor
+
+## TOOLS
+
+All tools are available:
+
+| Tool | Purpose |
+|------|---------|
+| read(path) | Read file contents |
+| write(path, content) | Create or overwrite file |
+| edit(path, old, new) | Replace text in file |
+| execute(command) | Run shell command |
+| eval(ruby) | Execute Ruby code |
+| task(prompt) | Delegate to sub-agent |
+| verify(path) | Check syntax and run tests |
+
+## PROCESS
+
+1. **Focus** - Ask which story to work on if not specified
+2. **Read** - Load the story from .elelem/backlog/
+3. **Test** - Write failing test first
+4. **Implement** - Minimal code to pass
+5. **Verify** - Run tests
+6. **Check** - Mark task complete in story file
+
+## EDITING TECHNIQUES
+
+Multi-line changes:
+
+```
+echo "DIFF" | patch -p1
+```
+
+Single-line changes:
+
+```
+sed -i'' 's/old/new/' file
+```
+
+New files: use the write tool
+
+## SEARCH COMMANDS
+
+```
+rg -n "pattern" .           # text search
+fd -e rb .                  # file discovery
+sg -p 'def $NAME' -l ruby   # structural search
+```
+
+## TASK COMPLETION
+
+When a task is done, edit the story file:
+
+```markdown
+# Tasks
+
+* [x] Create FooService in lib/foo_service.rb  <- mark done
+* [ ] Add #bar method to handle X              <- next task
+```
+
+## GUIDELINES
+
+- Work on what the user asks for
+- One task at a time
+- Minimal diffs
+- No defensive code
+- Verify after every change
+
+## SEE ALSO
+
+elelem-modes(7), elelem-mode-review(7)
docs/modes/design.md
@@ -0,0 +1,76 @@
+# ELELEM-MODE-DESIGN(7)
+
+## NAME
+
+elelem-mode-design - research and plan implementation
+
+## SYNOPSIS
+
+```
+/mode design
+```
+
+## DESCRIPTION
+
+Design mode focuses the agent on researching and planning implementation for
+backlog stories. The agent explores the codebase, identifies patterns and
+extension points, then breaks stories into atomic tasks.
+
+## ROLE
+
+- Read stories from `.elelem/backlog/`
+- Explore codebase to understand existing patterns
+- Fill in the Tasks section of each story
+- Identify risks and dependencies
+
+## CONSTRAINTS
+
+**Allowed:**
+- read, glob, grep, task
+- execute (read-only commands)
+- edit (only files in .elelem/backlog/)
+
+**Blocked:**
+- Code changes
+- Test changes
+
+## PROCESS
+
+1. **Review** - Read stories in .elelem/backlog/
+2. **Explore** - Trace code paths, find extension points
+3. **Research** - Consider design options and trade-offs
+4. **Plan** - Break each story into implementation tasks
+5. **Update** - Edit story files to add Tasks
+
+## TASK FORMAT
+
+Tasks should be added to the story's `# Tasks` section:
+
+```markdown
+# Tasks
+
+* [ ] Create FooService in lib/foo_service.rb
+* [ ] Add #bar method to handle X
+* [ ] Write spec in spec/foo_service_spec.rb
+* [ ] Update config/routes.rb to add endpoint
+```
+
+## GUIDELINES
+
+- Tasks should be small, atomic, and independently testable
+- Order tasks by dependency (do X before Y)
+- Reference specific files to modify
+- Note if new files are needed
+- Consider test-first ordering
+
+## TRADE-OFF DIMENSIONS
+
+When designing, consider:
+
+- Simplicity vs Flexibility
+- Performance vs Readability
+- Coupling vs Cohesion
+
+## SEE ALSO
+
+elelem-modes(7), elelem-mode-build(7)
docs/modes/README.md
@@ -0,0 +1,74 @@
+# ELELEM-MODES(7)
+
+## NAME
+
+elelem-modes - system prompt modes
+
+## DESCRIPTION
+
+Modes adjust the agent's system prompt and behavior for different phases of
+development. Each mode focuses the agent on a specific task with appropriate
+constraints.
+
+## AVAILABLE MODES
+
+| Mode | Purpose | Constraints |
+|------|---------|-------------|
+| design | Research and plan implementation | Read-only, can edit backlog |
+| build | Execute tasks with TDD | All tools available |
+| review | Verify changes meet criteria | Read-only analysis |
+| verify | Demo feature to Product Owner | End-to-end testing |
+
+## SWITCHING MODES
+
+```
+/mode              # show current mode and list all modes
+/mode design       # switch to design mode
+/mode build        # switch to build mode
+```
+
+## MODE DOCUMENTATION
+
+* [design](design.md) - research and planning
+* [build](build.md) - implementation with TDD
+* [review](review.md) - code review against criteria
+* [verify](verify.md) - end-to-end verification
+
+## CUSTOM MODES
+
+Create custom modes by adding ERB templates to `.elelem/prompts/`:
+
+```
+.elelem/prompts/mymode.erb
+```
+
+The template has access to these variables:
+
+| Variable | Description |
+|----------|-------------|
+| `pwd` | Current working directory |
+| `platform` | Operating system |
+| `date` | Current date |
+| `git_info` | Git branch and status |
+| `repo_map` | Ctags-generated code map |
+| `agents_md` | Contents of AGENTS.md |
+| `elelem_source` | Path to elelem source |
+
+Example custom mode:
+
+```erb
+You are in documentation mode. Write clear, concise docs.
+
+# Role
+- Generate documentation for code
+- Follow the project's doc style
+
+# Environment
+pwd: <%= pwd %>
+date: <%= date %>
+<%= git_info %>
+```
+
+## SEE ALSO
+
+elelem-workflow(7), elelem-plugins(7)
docs/modes/review.md
@@ -0,0 +1,71 @@
+# ELELEM-MODE-REVIEW(7)
+
+## NAME
+
+elelem-mode-review - code review against criteria
+
+## SYNOPSIS
+
+```
+/mode review
+```
+
+## DESCRIPTION
+
+Review mode focuses the agent on verifying that code changes meet the
+acceptance criteria defined in the story. The agent performs a structured
+code review and reports findings.
+
+## ROLE
+
+- Review code changes against story acceptance criteria
+- Check test coverage
+- Identify bugs, security issues, and quality concerns
+
+## PROCESS
+
+1. **Context** - Read the story from .elelem/backlog/
+2. **Diff** - Run `git diff` to see changes
+3. **Trace** - Read surrounding context
+4. **Verify** - Check each acceptance criterion
+5. **Report** - Summarize findings
+
+## REVIEW CHECKLIST
+
+- [ ] All tasks in story are checked off
+- [ ] Acceptance criteria are satisfied
+- [ ] Tests exist and pass
+- [ ] No logic errors or edge case bugs
+- [ ] No security vulnerabilities
+- [ ] No performance issues
+- [ ] SOLID principles followed
+- [ ] Code is readable and minimal
+
+## OUTPUT FORMAT
+
+```markdown
+## Story: <story file name>
+
+### Acceptance Criteria
+- [x] <criterion> - PASS
+- [ ] <criterion> - FAIL: <reason>
+
+### Issues
+#### [severity] filename:line - title
+<description and suggestion>
+
+Severity: critical | warning | nit
+
+### Verdict
+<approve | request changes | needs discussion>
+```
+
+## GUIDELINES
+
+- Be specific: cite file:line
+- Suggest fixes
+- Distinguish blocking from non-blocking issues
+
+## SEE ALSO
+
+elelem-modes(7), elelem-mode-verify(7)
docs/modes/verify.md
@@ -0,0 +1,65 @@
+# ELELEM-MODE-VERIFY(7)
+
+## NAME
+
+elelem-mode-verify - end-to-end verification
+
+## SYNOPSIS
+
+```
+/mode verify
+```
+
+## DESCRIPTION
+
+Verify mode focuses the agent on demoing the feature as if presenting to a
+Product Owner. The agent performs end-to-end testing from the user's
+perspective and documents the results.
+
+## ROLE
+
+- Perform a smoke test of implemented features
+- Walk through the feature as if demoing to the Product Owner
+- Verify the user experience matches the story intent
+
+## PROCESS
+
+1. **Setup** - Identify what to demo from .elelem/backlog/
+2. **Execute** - Run the feature end-to-end
+3. **Observe** - Note behavior, output, any issues
+4. **Document** - Add demo notes to story file
+5. **Report** - Summarize for Product Owner
+
+## DEMO CHECKLIST
+
+- [ ] Feature works as described in story
+- [ ] Happy path completes successfully
+- [ ] Error cases are handled gracefully
+- [ ] Output/behavior matches user expectations
+
+## STORY UPDATE
+
+After demo, add to story file:
+
+```markdown
+# Demo Notes
+
+Verified: <date>
+Status: ACCEPTED | NEEDS WORK
+
+Observations:
+- <what was tested>
+- <what worked>
+- <what needs attention>
+```
+
+## GUIDELINES
+
+- Test from user perspective, not developer
+- Try realistic scenarios
+- Note any UX issues
+- Be honest about gaps
+
+## SEE ALSO
+
+elelem-modes(7), elelem-workflow(7)
docs/plugins/authoring.md
@@ -0,0 +1,399 @@
+# Plugin Authoring
+
+Step-by-step guides for creating each plugin type.
+
+## Tool Plugins
+
+Tools are functions the LLM can call. The LLM sees the tool name, description, and parameter schema.
+
+### Step 1: Create the file
+
+```ruby
+# ~/.elelem/plugins/weather.rb
+Elelem::Plugins.register(:weather) do |agent|
+end
+```
+
+### Step 2: Define the tool
+
+```ruby
+Elelem::Plugins.register(:weather) do |agent|
+  agent.toolbox.add("weather",
+    description: "Get current weather for a city",
+    params: {
+      city: { type: "string", description: "City name" }
+    },
+    required: ["city"]
+  ) do |args|
+    # Tool implementation
+  end
+end
+```
+
+### Step 3: Implement the logic
+
+The block receives `args` (a Hash) and must return a Hash:
+
+```ruby
+agent.toolbox.add("weather",
+  description: "Get current weather for a city",
+  params: {
+    city: { type: "string", description: "City name" }
+  },
+  required: ["city"]
+) do |args|
+  city = args["city"]
+  response = Net::HTTP.get(URI("https://wttr.in/#{city}?format=j1"))
+  data = JSON.parse(response)
+  {
+    city: city,
+    temp_c: data.dig("current_condition", 0, "temp_C"),
+    condition: data.dig("current_condition", 0, "weatherDesc", 0, "value")
+  }
+end
+```
+
+### Step 4: Add output formatting (optional)
+
+Use an after hook to display results to the user:
+
+```ruby
+agent.toolbox.after("weather") do |_args, result|
+  agent.terminal.say "  #{result[:city]}: #{result[:temp_c]}°C, #{result[:condition]}"
+end
+```
+
+### Complete example
+
+```ruby
+# ~/.elelem/plugins/weather.rb
+Elelem::Plugins.register(:weather) do |agent|
+  agent.toolbox.add("weather",
+    description: "Get current weather for a city",
+    params: {
+      city: { type: "string", description: "City name" }
+    },
+    required: ["city"]
+  ) do |args|
+    city = args["city"]
+    response = Net::HTTP.get(URI("https://wttr.in/#{city}?format=j1"))
+    data = JSON.parse(response)
+    {
+      city: city,
+      temp_c: data.dig("current_condition", 0, "temp_C"),
+      condition: data.dig("current_condition", 0, "weatherDesc", 0, "value")
+    }
+  end
+
+  agent.toolbox.after("weather") do |_args, result|
+    agent.terminal.say "  #{result[:city]}: #{result[:temp_c]}°C, #{result[:condition]}"
+  end
+end
+```
+
+---
+
+## Command Plugins
+
+Commands are slash commands invoked by the user (not the LLM).
+
+### Step 1: Create the file
+
+```ruby
+# ~/.elelem/plugins/todo.rb
+Elelem::Plugins.register(:todo) do |agent|
+end
+```
+
+### Step 2: Register the command
+
+```ruby
+Elelem::Plugins.register(:todo) do |agent|
+  agent.commands.register("todo", description: "Show todo list") do |args|
+    # Command implementation
+  end
+end
+```
+
+The block receives the argument string after the command name.
+
+### Step 3: Implement the logic
+
+```ruby
+agent.commands.register("todo", description: "Manage todo list") do |args|
+  case args&.strip
+  when nil, ""
+    todos = File.readlines("TODO.md").map(&:strip)
+    agent.terminal.say todos.join("\n")
+  when /^add (.+)/
+    File.open("TODO.md", "a") { |f| f.puts "- [ ] #{$1}" }
+    agent.terminal.say "  → added"
+  end
+end
+```
+
+### Step 4: Add tab completion (optional)
+
+```ruby
+agent.commands.register("todo",
+  description: "Manage todo list",
+  completions: -> { %w[add done list] }
+) do |args|
+  # ...
+end
+```
+
+### Complete example
+
+```ruby
+# ~/.elelem/plugins/todo.rb
+Elelem::Plugins.register(:todo) do |agent|
+  agent.commands.register("todo",
+    description: "Manage todo list",
+    completions: -> { %w[add list] }
+  ) do |args|
+    case args&.strip
+    when nil, "", "list"
+      if File.exist?("TODO.md")
+        agent.terminal.say File.read("TODO.md")
+      else
+        agent.terminal.say "  (no todos)"
+      end
+    when /^add (.+)/
+      File.open("TODO.md", "a") { |f| f.puts "- [ ] #{$1}" }
+      agent.terminal.say "  → added"
+    end
+  end
+end
+```
+
+---
+
+## Hook Plugins
+
+Hooks run before or after tool execution. Use them for logging, confirmation, or post-processing.
+
+### Before hooks
+
+Run before a tool executes. Return `false` to cancel execution.
+
+**Tool-specific:**
+
+```ruby
+Elelem::Plugins.register(:logger) do |agent|
+  agent.toolbox.before("execute") do |args|
+    File.open("commands.log", "a") { |f| f.puts args["command"] }
+  end
+end
+```
+
+**Global (all tools):**
+
+```ruby
+Elelem::Plugins.register(:audit) do |agent|
+  agent.toolbox.before do |args, tool_name:|
+    File.open("audit.log", "a") { |f| f.puts "#{Time.now} #{tool_name}" }
+  end
+end
+```
+
+### After hooks
+
+Run after a tool completes. Receive both args and result.
+
+**Tool-specific:**
+
+```ruby
+Elelem::Plugins.register(:notify) do |agent|
+  agent.toolbox.after("execute") do |args, result|
+    if result[:exit_status] != 0
+      system("notify-send", "Command failed", args["command"])
+    end
+  end
+end
+```
+
+**Global:**
+
+```ruby
+Elelem::Plugins.register(:timing) do |agent|
+  starts = {}
+
+  agent.toolbox.before do |_args, tool_name:|
+    starts[tool_name] = Time.now
+  end
+
+  agent.toolbox.after do |_args, _result, tool_name:|
+    elapsed = Time.now - starts[tool_name]
+    agent.terminal.say "  (#{tool_name}: #{elapsed.round(2)}s)"
+  end
+end
+```
+
+### Confirmation hook
+
+A common pattern is requiring confirmation before dangerous operations:
+
+```ruby
+# Name starts with zz_ to load last
+# ~/.elelem/plugins/zz_confirm.rb
+Elelem::Plugins.register(:confirm) do |agent|
+  agent.toolbox.before("execute") do |args|
+    agent.terminal.say "  run: #{args["command"]}"
+    response = agent.terminal.ask("  proceed? [y/n] ")
+    response.strip.downcase == "y"
+  end
+end
+```
+
+---
+
+## Provider Plugins
+
+Providers are LLM backends. They implement the `fetch` interface.
+
+### Step 1: Create the client class
+
+The client must implement:
+
+```ruby
+fetch(messages, tools = []) { |event| ... } -> Array<tool_calls>
+```
+
+**Messages** (OpenAI format):
+
+```ruby
+{ role: "system", content: "..." }
+{ role: "user", content: "..." }
+{ role: "assistant", content: "..." }
+{ role: "tool", tool_call_id: "...", content: "..." }
+```
+
+**Tools** (OpenAI format):
+
+```ruby
+{ type: "function", function: { name:, description:, parameters: } }
+```
+
+**Events** (yield to block):
+
+```ruby
+{ type: "saying", text: "..." }      # assistant response text
+{ type: "thinking", text: "..." }    # reasoning/thinking text
+{ type: "tool_call", id:, name:, arguments: }
+```
+
+**Return value:**
+
+```ruby
+[{ id: "...", name: "tool_name", arguments: { ... } }, ...]
+```
+
+### Step 2: Create the provider plugin
+
+```ruby
+# ~/.elelem/plugins/gemini.rb
+require_relative "gemini_client"
+
+Elelem::Providers.register(:gemini) do
+  GeminiClient.new(
+    model: ENV.fetch("GEMINI_MODEL", "gemini-pro"),
+    api_key: ENV.fetch("GEMINI_API_KEY")
+  )
+end
+```
+
+### Step 3: Implement the client
+
+```ruby
+# ~/.elelem/plugins/gemini_client.rb
+class GeminiClient
+  def initialize(model:, api_key:)
+    @model = model
+    @api_key = api_key
+  end
+
+  def fetch(messages, tools = [])
+    tool_calls = []
+
+    # Convert messages to Gemini format
+    body = build_request(messages, tools)
+
+    # Stream response
+    stream(body) do |chunk|
+      # Parse chunk and yield events
+      if chunk["text"]
+        yield(type: "saying", text: chunk["text"])
+      end
+
+      if chunk["functionCall"]
+        tc = parse_tool_call(chunk["functionCall"])
+        yield(type: "tool_call", **tc)
+        tool_calls << tc
+      end
+    end
+
+    tool_calls
+  end
+
+  private
+
+  def build_request(messages, tools)
+    # Convert to Gemini API format
+    {
+      contents: messages.map { |m| convert_message(m) },
+      tools: tools.map { |t| convert_tool(t) }
+    }
+  end
+
+  def stream(body)
+    # POST to Gemini API with streaming
+    # Parse SSE events and yield chunks
+  end
+
+  def parse_tool_call(fc)
+    {
+      id: SecureRandom.uuid,
+      name: fc["name"],
+      arguments: fc["args"]
+    }
+  end
+end
+```
+
+### Complete minimal example
+
+```ruby
+# ~/.elelem/plugins/echo.rb
+# A mock provider for testing
+
+class EchoClient
+  def fetch(messages, tools = [])
+    last = messages.last[:content]
+    yield(type: "saying", text: "You said: #{last}")
+    []
+  end
+end
+
+Elelem::Providers.register(:echo) do
+  EchoClient.new
+end
+```
+
+Use with: `elelem chat --provider echo`
+
+---
+
+## Agent API Reference
+
+Plugins receive an `agent` object with:
+
+| Method | Description |
+|--------|-------------|
+| `agent.toolbox` | Add tools and hooks |
+| `agent.commands` | Register slash commands |
+| `agent.terminal` | Output to user (`say`, `ask`, `markdown`) |
+| `agent.conversation` | Access message history |
+| `agent.client` | Current LLM client |
+| `agent.fork(system_prompt:)` | Create sub-agent |
+| `agent.turn(prompt)` | Get LLM response |
docs/plugins/examples.md
@@ -0,0 +1,161 @@
+# Plugin Examples
+
+Real plugins from the elelem codebase.
+
+## Tool with After Hook
+
+The `read` plugin displays file contents after reading:
+
+```ruby
+Elelem::Plugins.register(:read) do |agent|
+  agent.toolbox.add("read",
+    description: "Read file",
+    params: { path: { type: "string" } },
+    required: ["path"],
+    aliases: ["open"]
+  ) do |a|
+    path = Pathname.new(a["path"]).expand_path
+    path.exist? ? { content: path.read, path: a["path"] } : { error: "not found" }
+  end
+
+  agent.toolbox.after("read") do |_, result|
+    if result[:error]
+      agent.terminal.say "  ! #{result[:error]}"
+    else
+      agent.terminal.display_file(result[:path], fallback: result[:content])
+    end
+  end
+end
+```
+
+## Context Compaction Command
+
+The `compact` command summarizes conversation history:
+
+```ruby
+Elelem::Plugins.register(:compact) do |agent|
+  agent.commands.register("compact", description: "Compress context") do
+    response = agent.turn("Summarize: accomplishments, state, next steps. Brief.")
+    agent.conversation.clear!
+    agent.conversation.add(role: "user", content: "Context: #{response}")
+    agent.terminal.say "  → compacted"
+  end
+end
+```
+
+## Tool Chaining
+
+The `verify` plugin runs syntax checks and tests by calling other tools:
+
+```ruby
+module Elelem
+  module Verifiers
+    SYNTAX = {
+      ".rb" => "ruby -c %{path}",
+      ".py" => "python -m py_compile %{path}",
+      ".go" => "go vet %{path}",
+      ".ts" => "npx tsc --noEmit %{path}",
+      ".js" => "node --check %{path}",
+    }.freeze
+
+    def self.for(path)
+      cmds = []
+      ext = File.extname(path)
+      cmds << (SYNTAX[ext] % { path: path }) if SYNTAX[ext]
+      cmds << test_runner
+      cmds.compact
+    end
+
+    def self.test_runner
+      %w[bin/test script/test].find { |s| File.executable?(s) }
+    end
+  end
+
+  Plugins.register(:verify) do |agent|
+    agent.toolbox.add("verify",
+      description: "Verify file syntax and run tests",
+      params: { path: { type: "string" } },
+      required: ["path"]
+    ) do |a|
+      path = a["path"]
+      Verifiers.for(path).inject({verified: []}) do |memo, cmd|
+        agent.terminal.say agent.toolbox.header("execute", { "command" => cmd })
+        v = agent.toolbox.run("execute", { "command" => cmd })
+        break v.merge(path: path, command: cmd) if v[:exit_status] != 0
+
+        memo[:verified] << cmd
+        memo
+      end
+    end
+  end
+end
+```
+
+## Mode Switcher with Completion
+
+```ruby
+Elelem::Plugins.register(:mode) do |agent|
+  agent.commands.register("mode",
+    description: "Switch system prompt mode",
+    completions: -> { Elelem::SystemPrompt.available_modes }
+  ) do |args|
+    name = args&.strip
+    if name.nil? || name.empty?
+      current = agent.system_prompt.mode
+      modes = Elelem::SystemPrompt.available_modes.map { |m| m == current ? "*#{m}" : m }
+      agent.terminal.say modes.join(" ")
+    else
+      agent.system_prompt.switch(name)
+      agent.terminal.say "mode: #{name}"
+    end
+  end
+end
+```
+
+## Provider Plugin
+
+The Ollama provider:
+
+```ruby
+Elelem::Providers.register(:ollama) do
+  Elelem::Net::Ollama.new(
+    model: ENV.fetch("OLLAMA_MODEL", "gpt-oss:latest"),
+    host: ENV.fetch("OLLAMA_HOST", "localhost:11434")
+  )
+end
+```
+
+## MCP Tool Output Formatting
+
+Pretty-print JSON from MCP tools:
+
+```ruby
+Elelem::Plugins.register(:gitlab) do |agent|
+  agent.toolbox.after("gitlab_search") do |_args, result|
+    IO.popen(["jq", "-C", "."], "r+") do |io|
+      io.write(result.to_json)
+      io.close_write
+      agent.terminal.say(io.read)
+    end
+  end
+end
+```
+
+## Builtin Commands
+
+Simple commands for common operations:
+
+```ruby
+Elelem::Plugins.register(:builtins) do |agent|
+  agent.commands.register("exit", description: "Exit elelem") { exit(0) }
+
+  agent.commands.register("clear", description: "Clear conversation history") do
+    agent.conversation.clear!
+    agent.terminal.say "  → context cleared"
+  end
+
+  agent.commands.register("help", description: "Show available commands") do
+    agent.terminal.say agent.commands.map { |name, desc| "#{name.ljust(12)} #{desc}" }.join("\n")
+  end
+end
+```
docs/plugins/README.md
@@ -0,0 +1,29 @@
+# Plugins
+
+Plugins extend elelem with custom functionality. There are four types:
+
+| Type | Purpose | Registry |
+|------|---------|----------|
+| [Tool](authoring.md#tool-plugins) | Functions the LLM can call | `agent.toolbox.add` |
+| [Command](authoring.md#command-plugins) | Slash commands for the user | `agent.commands.register` |
+| [Hook](authoring.md#hook-plugins) | Before/after tool execution | `agent.toolbox.before/after` |
+| [Provider](authoring.md#provider-plugins) | LLM backends | `Elelem::Providers.register` |
+
+## Location
+
+- `~/.elelem/plugins/` - user global (all projects)
+- `.elelem/plugins/` - project local
+
+## Basic Structure
+
+```ruby
+# ~/.elelem/plugins/myplugin.rb
+Elelem::Plugins.register(:myplugin) do |agent|
+  # add tools, commands, hooks
+end
+```
+
+## Guides
+
+- [Authoring](authoring.md) - step-by-step plugin creation
+- [Examples](examples.md) - real plugins from the codebase
docs/configuration.md
@@ -0,0 +1,27 @@
+# Configuration
+
+Elelem uses convention over configuration. Most behavior comes from file locations and environment variables.
+
+## Directory Structure
+
+**User global** (`~/.elelem/`):
+- `plugins/` - plugins loaded for all projects
+- `mcp.json` - global MCP servers
+
+**Project local** (`.elelem/`):
+- `plugins/` - project-specific plugins
+- `prompts/` - custom mode templates (ERB)
+- `backlog/` - user stories for workflow
+- `mcp.json` - project MCP servers
+
+## Plugin Loading Order
+
+1. `lib/elelem/plugins/` (built-in)
+2. `~/.elelem/plugins/` (user global)
+3. `.elelem/plugins/` (project local)
+
+Later plugins override earlier ones. Plugins starting with `zz_` load last.
+
+## Project Instructions
+
+`AGENTS.md` provides project-specific instructions. Elelem searches up the directory tree from the current working directory.
docs/getting-started.md
@@ -0,0 +1,39 @@
+# Getting Started
+
+## First Run
+
+```
+gem install elelem
+cd your-project
+elelem chat
+```
+
+Elelem requires a git repository and an LLM provider. By default it uses Ollama on localhost:11434.
+
+## Your First Conversation
+
+```
+you: What files are in this project?
+```
+
+The agent uses its tools to explore and respond. Type `/help` to see available commands.
+
+## Project Instructions
+
+Create an `AGENTS.md` file at your repository root to give the agent project-specific instructions:
+
+```markdown
+# Project Instructions
+
+- Use 2 spaces for indentation
+- Run `bin/test` after changes
+- Follow TDD
+```
+
+Elelem searches up the directory tree for this file.
+
+## Next Steps
+
+- [Workflow](workflow.md) - learn the development cycle
+- [Configuration](configuration.md) - customize elelem
+- [Plugins](plugins/) - extend with custom tools
docs/mcp.md
@@ -0,0 +1,53 @@
+# MCP Integration
+
+Elelem supports the Model Context Protocol for connecting to external tool servers.
+
+## Configuration
+
+Create `~/.elelem/mcp.json` (global) or `.elelem/mcp.json` (project):
+
+```json
+{
+  "mcpServers": {
+    "server-name": {
+      "command": "path/to/server"
+    }
+  }
+}
+```
+
+## Server Types
+
+**Stdio** - communicates via stdin/stdout:
+
+```json
+{
+  "mcpServers": {
+    "myserver": {
+      "command": "npx",
+      "args": ["@example/mcp-server"]
+    }
+  }
+}
+```
+
+**HTTP** - communicates via HTTP with SSE:
+
+```json
+{
+  "mcpServers": {
+    "myserver": {
+      "type": "http",
+      "url": "https://api.example.com/mcp"
+    }
+  }
+}
+```
+
+## OAuth
+
+HTTP servers support OAuth automatically. Elelem handles the browser flow, token storage, and refresh.
+
+## Debugging
+
+Logs are written to `~/.elelem/mcp.log`.
docs/README.md
@@ -0,0 +1,18 @@
+# Elelem Documentation
+
+Minimal coding agent for the command line.
+
+## Contents
+
+- [Getting Started](getting-started.md) - installation and first run
+- [Workflow](workflow.md) - plan/design/build/review/verify cycle
+- [Configuration](configuration.md) - config files and environment variables
+- [Modes](modes/) - system prompt modes
+- [Plugins](plugins/) - extending elelem with custom tools
+- [MCP](mcp.md) - Model Context Protocol integration
+- [Reference](reference.md) - tool schemas and commands
+
+## See Also
+
+- [README](../README.md) - project overview
+- [CHANGELOG](../CHANGELOG.md) - version history
docs/reference.md
@@ -0,0 +1,25 @@
+# Reference
+
+## Commands
+
+| Command | Description |
+|---------|-------------|
+| /clear | Clear conversation history |
+| /compact | Summarize and compress context |
+| /context | Show conversation state |
+| /exit | Exit elelem |
+| /help | List commands |
+| /init | Generate AGENTS.md |
+| /mode | Switch system prompt mode |
+| /provider | Switch LLM provider |
+| /reload | Hot-reload source code |
+| /shell | Shell session with transcript capture |
+| /tools | List available tools |
+
+## Built-in Tools
+
+See the [README](../README.md) for the complete tool reference.
+
+## Environment Variables
+
+See [Configuration](configuration.md) for environment variable reference.
docs/workflow.md
@@ -0,0 +1,163 @@
+# ELELEM-WORKFLOW(7)
+
+## NAME
+
+elelem-workflow - the plan/design/build/review/verify cycle
+
+## DESCRIPTION
+
+Elelem supports a structured workflow for feature development, inspired by
+agile practices. Each phase has a dedicated mode that adjusts the system
+prompt and available tools.
+
+## WORKFLOW DIAGRAM
+
+```
+                    +--------+
+                    |  Plan  |
+                    +---+----+
+                        |
+                        v
+                    +--------+
+                    | Design |
+                    +---+----+
+                        |
+                        v
+                    +--------+
+                    | Build  |
+                    +---+----+
+                        |
+                        v
+                    +--------+
+                    | Review |
+                    +---+----+
+                        |
+                        v
+                    +--------+
+                    | Verify |
+                    +--------+
+```
+
+## PHASES
+
+### Plan
+
+Create user stories in `.elelem/backlog/`. Each story is a markdown file
+with acceptance criteria and tasks.
+
+Example story:
+
+```markdown
+# Add logout button
+
+As a user, I want to log out so that I can end my session.
+
+## Acceptance Criteria
+
+- [ ] Button visible when logged in
+- [ ] Click logs user out
+- [ ] Redirects to home page
+
+## Tasks
+
+(filled in during design phase)
+```
+
+### Design
+
+Research and plan implementation. The agent explores the codebase, identifies
+extension points, and breaks the story into atomic tasks.
+
+```
+/mode design
+```
+
+Constraints:
+- Allowed: read, glob, grep, task, execute (read-only)
+- Blocked: code changes, test changes
+- Can only edit files in .elelem/backlog/
+
+### Build
+
+Execute tasks from the story using TDD:
+
+1. Write failing test
+2. Implement minimal code to pass
+3. Refactor if needed
+4. Mark task complete
+
+```
+/mode build
+```
+
+All tools available. Work through tasks one at a time.
+
+### Review
+
+Verify changes meet acceptance criteria:
+
+```
+/mode review
+```
+
+The agent checks:
+- All tasks completed
+- Acceptance criteria satisfied
+- Tests exist and pass
+- No logic errors or security issues
+- SOLID principles followed
+
+### Verify
+
+Demo the feature as if presenting to the Product Owner:
+
+```
+/mode verify
+```
+
+The agent performs end-to-end testing from the user's perspective and
+documents the results.
+
+## STORY FILES
+
+Stories live in `.elelem/backlog/` and follow this structure:
+
+```markdown
+# Story Title
+
+Brief description of the feature.
+
+## Acceptance Criteria
+
+- [ ] Criterion 1
+- [ ] Criterion 2
+
+## Tasks
+
+* [ ] Task 1
+* [ ] Task 2
+* [x] Completed task
+
+## Demo Notes
+
+Verified: 2026-01-15
+Status: ACCEPTED
+
+Observations:
+- Feature works as expected
+- Edge case X handled correctly
+```
+
+## SWITCHING MODES
+
+Use the `/mode` command:
+
+```
+/mode              # show current mode
+/mode build        # switch to build mode
+/mode design       # switch to design mode
+```
+
+## SEE ALSO
+
+elelem-modes(7), elelem-plugins(7)