toj is now on the global PATH as /usr/local/bin/toj, so its scope boundary
had to stop being "the absolute path is inconvenient to type" and start
being a rule. Its repo and settings verbs operate on the workspace root; run
from inside this repo they answer about the wrong tree.
Both spellings are denied, bare and absolute, because a deny with one
spelling left open is decorative.
Co-Authored-By: Claude <noreply@anthropic.com>
No repo here scanned for committed credentials. The hook is self-contained
rather than delegating to a Makefile, because this repo has none and a hook
reaching into a sibling repo breaks the moment this one is cloned elsewhere.
Scans the outgoing range rather than full history: history carries settled
findings — test fixtures, vendored third-party code — and a gate that fails
on something unfixable gets bypassed within a week.
Setting core.hooksPath means pql init must replant its replication shims into
.githooks, which is why they are gitignored here alongside the tracked
pre-push. Same layout pql itself uses.
Co-Authored-By: Claude <noreply@anthropic.com>
This repo's Work tracking section still described the reversed policy --
that tickets and decisions live in the workspace vault and this repo's
trees stay empty. That was overturned the same day: repo vaults are
standalone and a repo's work travels with a clone, because the changelog
is committed.
Every other repo was corrected at the time; this one was missed because
the search for the offending phrase used a fixed string and the phrase
happened to wrap across a line break here. Worth noting as a search
failure rather than a writing one -- five files were checked, four
matched, and the fifth was reported clean.
Decision ids are also qualified now. They are per-vault sequences, so a
bare D-15 here will mean this repo's D-15 the moment this repo records
one; pql already holds D-1 through D-31 against the workspace's D-1
through D-21, all of them unrelated.
Co-Authored-By: Claude <noreply@anthropic.com>
One agent doc per repo, and it is CLAUDE.md. This repo carried two --
one at the root and one under webber-api/ -- which is the drift problem
in its purest form: two documents, one subject, and no way to know which
the last reader trusted. Written fresh rather than reformatted.
README.md linked to webber-api/AGENTS.md, so that pointer moves with the
file rather than dangling.
The architecture section states the method used to establish what is
live -- import the app inside the container and read sys.modules -- and
then the case where that method fails here. src/domains/tools is absent
from a cold snapshot and is entirely live: each agent's _register_tools
imports its tool package from inside the method body, on every
/agents/run. Absence from a snapshot taken before any request is served
is a timing artifact, not evidence of death, and deleting on that basis
would have removed the tool layer.
Co-Authored-By: Claude <noreply@anthropic.com>
Commits a .claude/settings.json rather than leaving permissions to
per-developer local state, and initialises a pql vault for this repo's
tickets and internal decisions.
Every git deny rule appears in both the `git <verb>` and `git * <verb>`
forms. Only the second catches `git -C <path>`, and without it the whole
deny list is decorative -- it looks like a policy and stops nothing.
The allow list carries pql's absolute path alongside the bare name.
pql is installed to ~/.local/bin, which is on the login PATH but not the
one a non-interactive shell gets, so the bare-name rules match nothing on
their own and every call would prompt anyway.
.gitignore now covers .claude/settings.local.json, which is machine-local
and must never be shared. `pql init` contributed the .pql/* rules with an
exception for the changelog, which is the replication log of record and
has to be committed for tickets to travel with a clone.
Co-Authored-By: Claude <noreply@anthropic.com>
mistral-nemo-large holds ~9.2 GB of the 11 GB card it shares with Speaches,
which starves Whisper and breaks voice transcription. gemma4:e2b holds
1.9 GB and is faster. The deployed stack already overrides this via
OLLAMA_AGENT_MODEL; this aligns the default so a deployment without that
override does not reintroduce the contention.
Co-Authored-By: Claude <noreply@anthropic.com>
The deployed agent model is gemma4:e2b; these references still named
mistral-nemo, so the setup and troubleshooting steps checked for a model
that is no longer expected to be present.
Co-Authored-By: Claude <noreply@anthropic.com>
Patch release for the network migration: docker-hostname config
defaults for Tatlock/SearXNG and CI image push via the
git.schweitz.net registry route.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The homelab is retiring *.schweitz.internal and will rebind host ports
to 127.0.0.1, so container-to-container traffic must use container
names on the docker-dataplane network. Switch defaults from host
IP:port to http://tatlock:8000 and http://searxng:8080 (SearXNG's
internal port is 8080; 8087 is only the host-published port).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The .internal registry domain is being retired; git.schweitz.net now
serves the registry without SSO on /v2/.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- Event-based streaming for task agent
- Retry logic when LLM responds without calling tools
- Hardened prompts to enforce tool use
- Working directory context in all agent prompts
- Project paused: local LLMs not capable enough for agentic use
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Remove mode=mode.value from trace_span calls (trace_span only accepts
name and logger parameters)
- Add TestPermissionModeIntegration tests that verify mode string->enum
conversion works correctly through the full request flow
- Add TestAgentMethodSignatures tests that verify function signatures
match expected interfaces (catches invalid kwargs at test time)
These tests would have caught both the mode string/enum issue and the
trace_span invalid kwarg issue before they hit production.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The BaseSchema has use_enum_values=True which makes Pydantic store
enum values as strings. Added _get_mode() helper to convert back to
PermissionMode enum before passing to agent methods.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add ~/.webber/config.toml for persistent settings
- Support api.url, api.key, cli.mode, cli.stream, history.file
- Environment variables override config file values
- Add 'config' command to show settings and init config file
- Update all commands to use config defaults
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add save-only endpoint (POST /conversations/{id}/save) for persisting
messages without triggering agent execution
- Add sessions command to list previous conversation sessions
- Add --resume flag to chat command for resuming sessions by ID
- Buffer streamed responses and save after completion
- Update AGENTS.md with session commands and remove outdated limitation
- Add 3 new tests for save endpoint (208 total)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Permission Modes:
- Add default/plan/auto_accept modes controlling tool access
- Plan mode restricts Task agent to read-only tools only
- Auto-accept mode bypasses approval prompts (with confirmation)
Approval Scaffolding:
- Add ApprovalRule/ApprovalRuleSet for granular tool control
- Pattern-based matching on tool name and arguments
- Default rules for common safe/dangerous patterns
- Prep for future bidirectional approval flow
CLI Refactor:
- Default to Task agent (main orchestrator)
- Add --mode flag and runtime mode switching
- Integrate prompt_toolkit for better UX:
- Persistent command history (~/.webber_history)
- Tab completion for commands and file paths
- Auto-suggest from history
- Deprecate standalone 'explore' command
Other:
- Split CHANGELOG.md into per-package files
- Update AGENTS.md release procedure for both packages
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- @with_retry decorator and retry_async() function
- Exponential backoff with jitter
- Retries on: timeout, connection errors, HTTP 429/5xx
- Web search tool now retries on network failures
- Configurable via RETRY_MAX_ATTEMPTS, RETRY_BASE_DELAY, RETRY_MAX_DELAY
- 29 new tests (205 total passing)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- litellm had dependency conflicts with pydantic-ai
- tiktoken is lighter and already required by pydantic-ai
- Updated documentation (README.md, architecture.md)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add PlanAgentImpl with read-only tools only
- System prompts optimized for architecture planning
- Outputs step-by-step implementation plans with critical files
- 15 unit tests for registration, tools, and API
- Update COVERAGE.md to ~70% complete
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Document the correct order for creating releases:
1. Update pyproject.toml version
2. Update CHANGELOG.md
3. Commit version bump
4. Create tag
5. Push with --tags
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add pytest markers (integration, e2e, slow) with skip logic
- Add command line options (--run-integration, --run-e2e)
- Create sample_project and sample_project_with_bug fixtures
- Add test_integration.py with 10 LLM tests
- Add test_e2e.py with 12 API server tests
- Update COVERAGE.md to reflect ~65% complete
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Update COVERAGE.md to reflect completed features (now ~60%)
- Update main README with features and tools list
- Update CLI README with streaming options
- Expand API tests from 5 to 11 (add stream endpoint tests)
- Add 14 security tests for path traversal, command injection
- Total tests: 109 (up from 88)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add WebSearchTool that queries the self-hosted SearXNG metasearch engine
for current information, documentation, and facts beyond training data.
- Add SEARXNG_URL and SEARXNG_TIMEOUT config settings
- Create WebSearchTool with query, num_results, categories params
- Register web_search tool with explore agent
- Add 10 tests for search functionality
Usage: Agents can now use web_search(query="...") to find current info.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add real-time streaming support for agent responses using Server-Sent
Events (SSE). Responses now appear as they're generated instead of
waiting for completion.
- Add run_stream method to BaseAgent and ExploreAgentImpl
- Add /agents/stream SSE endpoint to API router
- Add run_agent_stream method to CLI client
- Add --stream flag to chat and explore commands (enabled by default)
- Use --no-stream for batch mode with spinner
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
New tools for code modification:
- EditFileTool: find-and-replace with safety checks (unique match required)
- WriteFileTool: create/overwrite files with path validation
- BashTool: full bash with controlled write access
Security controls on BashTool:
- Allowed: mkdir, touch, cp, mv, rm (single files), git, pip, pytest
- Forbidden: sudo, curl, wget, ssh, rm -rf, chmod 777
Includes 39 new tests (78 total now passing).
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Structure webber into three independent subprojects:
- webber-api/: FastAPI backend server with all agent code
- webber-cli/: Standalone CLI client (renamed from cli/ to webber_cli/)
- webber-sandbox/: Test project for functional testing
Key changes:
- Each subproject has its own .venv (Python 3.12+)
- Added sandbox.sh for managing test project templates
- Created sandbox-templates/ with calculator-cli and empty starter
- Updated CI/CD for prefixed tags (api/v*, cli/v*)
- Added comprehensive AGENTS.md with operational instructions
- Added gitignore filtering to glob and grep tools
- Created pyproject.toml for each subproject
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Implements the first Claude-like agent for codebase exploration:
Core Features:
- Explore agent with glob, grep, read, and bash tools
- Native PydanticAI tool calling with Ollama/Mistral Nemo
- Sanitized Ollama provider (fixes content:null issue)
- REST API endpoints for agent execution
Tool Infrastructure:
- BaseTool abstract class with ToolResult dataclass
- ReadFileTool, GlobFilesTool, GrepContentTool, BashReadOnlyTool
- Path validation and sandboxing support
CLI Client (separate package for future extraction):
- webber-cli command with chat, explore, status commands
- Communicates with Webber API backend
- Rich console output with theming
Configuration:
- Dev server on port 8095 (production uses 8086)
- Mistral Nemo optimizations (temp 0.3, tool_choice required)
Tests: 24 tests covering tools and API endpoints
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add ruff linter configuration to pyproject.toml with modern Python 3.12 rules
- Add ruff~=0.9.4 to dev dependencies
- Fix all mypy type errors (Optional[] hints, Token types, Any returns)
- Auto-fix 54 ruff issues (import sorting, Optional -> X | None syntax)
- Create ProjectMeta dataclass for single source of truth from pyproject.toml
- Write comprehensive README.md with setup, config, and development docs
- Update main.py to use settings.app_description from pyproject.toml
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Replace temporary implementation plan with permanent architecture
documentation covering project structure, core patterns, and
deployment details.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Use Optional[list[str]] with None default for allowed_paths
- Add env_parse_none_str="" to treat empty strings as None
- Add effective_allowed_paths property for safe access
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add .gitea/workflows/build.yml for tag-triggered builds
- Add Dockerfile for containerized deployment (port 8086)
- Add .dockerignore to keep image lean
- Add CHANGELOG.md following Keep a Changelog format
- Update AGENTS.md with deployment verification URL
Build pipeline:
1. Create Gitea release on v* tag
2. Build and push Docker image to git.schweitz.internal
3. Trigger Watchtower for automatic deployment
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>