localist 0.1.0__tar.gz

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 (33) hide show
  1. localist-0.1.0/.env.example +32 -0
  2. localist-0.1.0/.gitignore +42 -0
  3. localist-0.1.0/CHANGELOG.md +24 -0
  4. localist-0.1.0/LICENSE +21 -0
  5. localist-0.1.0/MANIFEST.in +2 -0
  6. localist-0.1.0/PKG-INFO +269 -0
  7. localist-0.1.0/README.md +224 -0
  8. localist-0.1.0/pyproject.toml +96 -0
  9. localist-0.1.0/src/localist/__init__.py +43 -0
  10. localist-0.1.0/src/localist/agent.py +428 -0
  11. localist-0.1.0/src/localist/cli.py +270 -0
  12. localist-0.1.0/src/localist/config.py +119 -0
  13. localist-0.1.0/src/localist/confirmation.py +99 -0
  14. localist-0.1.0/src/localist/exceptions.py +71 -0
  15. localist-0.1.0/src/localist/logger.py +107 -0
  16. localist-0.1.0/src/localist/protocol.py +211 -0
  17. localist-0.1.0/src/localist/registry.py +258 -0
  18. localist-0.1.0/src/localist/sandbox.py +80 -0
  19. localist-0.1.0/src/localist/tools/__init__.py +9 -0
  20. localist-0.1.0/src/localist/tools/filesystem.py +197 -0
  21. localist-0.1.0/src/localist/tools/os_tools.py +148 -0
  22. localist-0.1.0/src/localist/tools/shell.py +118 -0
  23. localist-0.1.0/src/localist/tools/web.py +185 -0
  24. localist-0.1.0/src/localist/ui/__init__.py +6 -0
  25. localist-0.1.0/src/localist/ui/server.py +271 -0
  26. localist-0.1.0/src/localist/ui/static/app.js +448 -0
  27. localist-0.1.0/src/localist/ui/static/index.html +130 -0
  28. localist-0.1.0/src/localist/ui/static/style.css +779 -0
  29. localist-0.1.0/tests/__init__.py +1 -0
  30. localist-0.1.0/tests/test_agent.py +149 -0
  31. localist-0.1.0/tests/test_registry.py +89 -0
  32. localist-0.1.0/tests/test_sandbox.py +79 -0
  33. localist-0.1.0/tests/test_tools.py +152 -0
@@ -0,0 +1,32 @@
1
+ # Environment configuration for Localist
2
+ # Copy this file to .env and fill in your values
3
+
4
+ # ── Ollama ──────────────────────────────────────────────────────────────────
5
+ OLLAMA_BASE_URL=http://localhost:11434
6
+ LOCALIST_MODEL=qwen2.5:7b
7
+
8
+ # ── Workspace ────────────────────────────────────────────────────────────────
9
+ # All file operations are sandboxed inside this directory
10
+ LOCALIST_WORKSPACE_ROOT=./workspace
11
+
12
+ # ── Agent loop ───────────────────────────────────────────────────────────────
13
+ LOCALIST_MAX_ITERATIONS=20
14
+
15
+ # ── Safety ───────────────────────────────────────────────────────────────────
16
+ # Set to false to disable confirmation prompts (e.g., in automated pipelines)
17
+ LOCALIST_REQUIRE_CONFIRMATION=true
18
+
19
+ # Comma-separated list of tools that require explicit confirmation
20
+ LOCALIST_CONFIRMATION_TOOLS=file_delete,shell_exec,process_kill
21
+
22
+ # ── Logging ──────────────────────────────────────────────────────────────────
23
+ LOCALIST_LOG_DIR=./logs
24
+ LOCALIST_LOG_LEVEL=INFO
25
+
26
+ # ── Web Search ───────────────────────────────────────────────────────────────
27
+ # Optional: set to use Brave Search API instead of DuckDuckGo
28
+ BRAVE_API_KEY=
29
+
30
+ # ── Web UI (optional, requires: pip install localist[ui]) ────────────────────
31
+ LOCALIST_UI_HOST=127.0.0.1
32
+ LOCALIST_UI_PORT=7860
@@ -0,0 +1,42 @@
1
+ # Python
2
+ __pycache__/
3
+ *.py[cod]
4
+ *$py.class
5
+ *.so
6
+ *.egg
7
+ *.egg-info/
8
+ dist/
9
+ build/
10
+ .eggs/
11
+ .venv/
12
+ venv/
13
+ env/
14
+
15
+ # Distribution
16
+ dist/
17
+ *.whl
18
+ *.tar.gz
19
+
20
+ # Environment
21
+ .env
22
+ !.env.example
23
+
24
+ # Localist runtime
25
+ workspace/
26
+ logs/
27
+
28
+ # Testing
29
+ .pytest_cache/
30
+ .coverage
31
+ htmlcov/
32
+ .mypy_cache/
33
+ .ruff_cache/
34
+
35
+ # IDE
36
+ .vscode/
37
+ .idea/
38
+ *.swp
39
+ *.swo
40
+
41
+ # macOS
42
+ .DS_Store
@@ -0,0 +1,24 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project will be documented in this file.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
+
8
+ ## [0.1.0] - 2026-09-13
9
+
10
+ ### Added
11
+ - Initial release of `localist`
12
+ - ReAct agent loop with dual protocol support (native tool-calling + text-based)
13
+ - Filesystem tools: `file_read`, `file_write`, `file_append`, `file_delete`, `list_dir`
14
+ - Web tools: `web_search` (DuckDuckGo + Brave Search), `web_fetch`
15
+ - Shell tool: `shell_exec` with allowlist/denylist safety
16
+ - OS tools: `clipboard_get`, `clipboard_set`, `notify`, `process_list`, `process_kill`
17
+ - Filesystem sandbox jail (path traversal protection)
18
+ - Human-in-the-loop confirmation gate for destructive operations
19
+ - Structured JSON audit logging
20
+ - `@register_tool` decorator for custom tools
21
+ - Rich CLI with `localist` entry point
22
+ - Optional FastAPI web UI (`pip install localist[ui]`)
23
+ - Automatic model capability detection (native vs. text-protocol)
24
+ - Retry/repair logic for malformed JSON tool calls
localist-0.1.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Localist Contributors
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 all
13
+ 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 THE
21
+ SOFTWARE.
@@ -0,0 +1,2 @@
1
+ recursive-include src/localist/ui/static *
2
+ include README.md LICENSE CHANGELOG.md .env.example
@@ -0,0 +1,269 @@
1
+ Metadata-Version: 2.5
2
+ Name: localist
3
+ Version: 0.1.0
4
+ Summary: Local agentic framework on Ollama — filesystem, web, shell & OS tools with a sandboxed ReAct loop
5
+ License: MIT
6
+ License-File: LICENSE
7
+ Keywords: agent,agentic,autonomous,llm,local-ai,ollama,react,tool-calling
8
+ Classifier: Development Status :: 3 - Alpha
9
+ Classifier: Environment :: Console
10
+ Classifier: Intended Audience :: Developers
11
+ Classifier: License :: OSI Approved :: MIT License
12
+ Classifier: Programming Language :: Python :: 3.10
13
+ Classifier: Programming Language :: Python :: 3.11
14
+ Classifier: Programming Language :: Python :: 3.12
15
+ Classifier: Programming Language :: Python :: 3.13
16
+ Classifier: Programming Language :: Python :: 3.14
17
+ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
18
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
19
+ Requires-Python: >=3.10
20
+ Requires-Dist: duckduckgo-search>=6.0
21
+ Requires-Dist: httpx>=0.27
22
+ Requires-Dist: ollama>=0.3
23
+ Requires-Dist: plyer>=2.1
24
+ Requires-Dist: psutil>=5.9
25
+ Requires-Dist: pydantic-settings>=2.0
26
+ Requires-Dist: pydantic>=2.0
27
+ Requires-Dist: pyperclip>=1.8
28
+ Requires-Dist: python-dotenv>=1.0
29
+ Requires-Dist: rich>=13.0
30
+ Requires-Dist: trafilatura>=1.12
31
+ Provides-Extra: dev
32
+ Requires-Dist: build>=1.0; extra == 'dev'
33
+ Requires-Dist: mypy>=1.10; extra == 'dev'
34
+ Requires-Dist: pytest-asyncio>=0.23; extra == 'dev'
35
+ Requires-Dist: pytest-cov>=5.0; extra == 'dev'
36
+ Requires-Dist: pytest>=8.0; extra == 'dev'
37
+ Requires-Dist: ruff>=0.4; extra == 'dev'
38
+ Requires-Dist: twine>=5.0; extra == 'dev'
39
+ Requires-Dist: types-psutil; extra == 'dev'
40
+ Provides-Extra: ui
41
+ Requires-Dist: fastapi>=0.111; extra == 'ui'
42
+ Requires-Dist: python-multipart>=0.0.9; extra == 'ui'
43
+ Requires-Dist: uvicorn[standard]>=0.30; extra == 'ui'
44
+ Description-Content-Type: text/markdown
45
+
46
+ # localist
47
+
48
+ **Local agentic framework on Ollama** — give your local LLM sandboxed access to filesystem, web, shell, and OS tools via a ReAct reasoning loop.
49
+
50
+ [![PyPI version](https://badge.fury.io/py/localist.svg)](https://pypi.org/project/localist/)
51
+ [![Python 3.11+](https://img.shields.io/badge/python-3.11+-blue.svg)](https://python.org)
52
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
53
+
54
+ ---
55
+
56
+ ## What is this?
57
+
58
+ `localist` is a Python library that wraps any [Ollama](https://ollama.ai)-served model and gives it the ability to autonomously:
59
+
60
+ - 📂 **Read / write / delete files** inside a sandboxed workspace
61
+ - 🌐 **Search the web** (DuckDuckGo, or Brave Search API)
62
+ - 🖥️ **Run shell commands** (behind a denylist + confirmation gate)
63
+ - 📋 **Use OS features** — clipboard, notifications, process management
64
+
65
+ It implements a **ReAct-style loop** (Reason → Act → Observe → repeat) and supports both models with native tool-calling (Qwen2.5, Llama 3.1+) and text-based tool-calling for any other model.
66
+
67
+ ---
68
+
69
+ ## Quick Start
70
+
71
+ ```bash
72
+ # Install
73
+ pip install localist
74
+
75
+ # Make sure Ollama is running
76
+ ollama serve
77
+ ollama pull qwen2.5:7b
78
+
79
+ # Run a task
80
+ localist --task "Create a file called hello.txt with today's date, then list the workspace"
81
+ ```
82
+
83
+ ---
84
+
85
+ ## Installation
86
+
87
+ ```bash
88
+ # Core library + CLI
89
+ pip install localist
90
+
91
+ # With web UI (FastAPI + Uvicorn)
92
+ pip install "localist[ui]"
93
+
94
+ # Development
95
+ pip install "localist[dev]"
96
+ ```
97
+
98
+ ---
99
+
100
+ ## Usage
101
+
102
+ ### Python API
103
+
104
+ ```python
105
+ from localist import Agent
106
+
107
+ agent = Agent(model="qwen2.5:7b", workspace_root="./workspace")
108
+ result = agent.run("Search for the latest Python release and save a summary to workspace/python_news.txt")
109
+ print(result)
110
+ ```
111
+
112
+ ### Streaming events
113
+
114
+ ```python
115
+ from localist import Agent
116
+ from localist.agent import ToolCallEvent, FinalAnswerEvent
117
+
118
+ agent = Agent(model="qwen2.5:7b")
119
+
120
+ for event in agent.stream("Summarise all .txt files in workspace"):
121
+ if isinstance(event, ToolCallEvent):
122
+ print(f" 🔧 Calling: {event.tool}({event.args})")
123
+ elif isinstance(event, FinalAnswerEvent):
124
+ print(f"\n✅ Answer:\n{event.content}")
125
+ ```
126
+
127
+ ### Custom tools
128
+
129
+ ```python
130
+ from localist import Agent, register_tool
131
+
132
+ @register_tool
133
+ def count_words(text: str) -> int:
134
+ """Count the number of words in a text string.
135
+
136
+ Args:
137
+ text: The input text to count words in.
138
+ """
139
+ return len(text.split())
140
+
141
+ agent = Agent(model="qwen2.5:7b")
142
+ result = agent.run("Count the words in 'The quick brown fox jumps over the lazy dog'")
143
+ ```
144
+
145
+ ### CLI
146
+
147
+ ```bash
148
+ # Single task
149
+ localist --task "Create a Python script that generates the Fibonacci sequence"
150
+
151
+ # Custom model and workspace
152
+ localist --task "..." --model llama3.1:8b --workspace ~/myproject
153
+
154
+ # Interactive REPL
155
+ localist --interactive
156
+
157
+ # Web UI (requires pip install localist[ui])
158
+ localist --ui
159
+
160
+ # List available Ollama models
161
+ localist --list-models
162
+
163
+ # Disable confirmation prompts (for scripts/automation)
164
+ localist --task "..." --no-confirm
165
+ ```
166
+
167
+ ---
168
+
169
+ ## Tools
170
+
171
+ | Tool | Description | Confirmation required? |
172
+ |---|---|---|
173
+ | `file_read` | Read file contents | No |
174
+ | `file_write` | Create/overwrite a file | No (overwrite) |
175
+ | `file_append` | Append to a file | No |
176
+ | `file_delete` | Delete a file | **Yes** |
177
+ | `list_dir` | List directory contents | No |
178
+ | `web_search` | Search web (DuckDuckGo / Brave) | No |
179
+ | `web_fetch` | Fetch and extract text from URL | No |
180
+ | `shell_exec` | Run a shell command | **Yes** |
181
+ | `clipboard_get` | Read clipboard | No |
182
+ | `clipboard_set` | Write clipboard | No |
183
+ | `notify` | OS desktop notification | No |
184
+ | `process_list` | List running processes | No |
185
+ | `process_kill` | Terminate a process by PID | **Yes** |
186
+
187
+ ---
188
+
189
+ ## Configuration
190
+
191
+ Copy `.env.example` to `.env` and edit:
192
+
193
+ ```env
194
+ LOCALIST_MODEL=qwen2.5:7b
195
+ LOCALIST_WORKSPACE_ROOT=./workspace
196
+ LOCALIST_MAX_ITERATIONS=20
197
+ LOCALIST_REQUIRE_CONFIRMATION=true
198
+ BRAVE_API_KEY= # optional — enables Brave Search API
199
+ ```
200
+
201
+ All settings can also be passed programmatically:
202
+
203
+ ```python
204
+ from localist.config import LocalistConfig
205
+ from localist import Agent
206
+
207
+ cfg = LocalistConfig(model="llama3.1:8b", max_iterations=10, require_confirmation=False)
208
+ agent = Agent(config=cfg)
209
+ ```
210
+
211
+ ---
212
+
213
+ ## Safety
214
+
215
+ - **Filesystem jail**: every path is resolved against `workspace_root`; `..` traversal, symlink escapes, and absolute paths outside the workspace are rejected with `SandboxViolationError`.
216
+ - **Shell denylist**: `shell_exec` blocks `rm`, `sudo`, `curl`, `python`, shell interpreters, and other high-risk binaries. No `shell=True` anywhere.
217
+ - **Confirmation gate**: `file_delete`, `shell_exec`, and `process_kill` require explicit human approval (configurable).
218
+ - **Hard iteration cap**: the loop stops after `max_iterations` (default: 20) to prevent infinite loops.
219
+ - **Audit logging**: every tool call, result, and confirmation is written to `logs/audit_<date>.jsonl`.
220
+
221
+ ---
222
+
223
+ ## Model Recommendations
224
+
225
+ | Model | Tool-calling | Notes |
226
+ |---|---|---|
227
+ | `qwen2.5:7b` / `qwen2.5:32b` | Native | Best balance of speed and reliability |
228
+ | `llama3.1:8b` / `llama3.3:70b` | Native | Strong general reasoning |
229
+ | `hermes3` | Native | Optimised for agentic tasks |
230
+ | `mistral-nemo` | Native | Fast, solid tool support |
231
+ | Any other model | Text protocol | Automatic fallback with JSON repair |
232
+
233
+ ---
234
+
235
+ ## Build and Publish
236
+
237
+ ```bash
238
+ # Install build tools
239
+ pip install build twine
240
+
241
+ # Build
242
+ python -m build
243
+
244
+ # Validate
245
+ twine check dist/*
246
+
247
+ # Upload to TestPyPI
248
+ twine upload --repository testpypi dist/*
249
+
250
+ # Upload to PyPI
251
+ twine upload dist/*
252
+ ```
253
+
254
+ ---
255
+
256
+ ## Development
257
+
258
+ ```bash
259
+ git clone https://github.com/placeholder/localist
260
+ cd localist
261
+ pip install -e ".[dev]"
262
+ pytest tests/ -v
263
+ ```
264
+
265
+ ---
266
+
267
+ ## License
268
+
269
+ MIT — see [LICENSE](LICENSE).
@@ -0,0 +1,224 @@
1
+ # localist
2
+
3
+ **Local agentic framework on Ollama** — give your local LLM sandboxed access to filesystem, web, shell, and OS tools via a ReAct reasoning loop.
4
+
5
+ [![PyPI version](https://badge.fury.io/py/localist.svg)](https://pypi.org/project/localist/)
6
+ [![Python 3.11+](https://img.shields.io/badge/python-3.11+-blue.svg)](https://python.org)
7
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
8
+
9
+ ---
10
+
11
+ ## What is this?
12
+
13
+ `localist` is a Python library that wraps any [Ollama](https://ollama.ai)-served model and gives it the ability to autonomously:
14
+
15
+ - 📂 **Read / write / delete files** inside a sandboxed workspace
16
+ - 🌐 **Search the web** (DuckDuckGo, or Brave Search API)
17
+ - 🖥️ **Run shell commands** (behind a denylist + confirmation gate)
18
+ - 📋 **Use OS features** — clipboard, notifications, process management
19
+
20
+ It implements a **ReAct-style loop** (Reason → Act → Observe → repeat) and supports both models with native tool-calling (Qwen2.5, Llama 3.1+) and text-based tool-calling for any other model.
21
+
22
+ ---
23
+
24
+ ## Quick Start
25
+
26
+ ```bash
27
+ # Install
28
+ pip install localist
29
+
30
+ # Make sure Ollama is running
31
+ ollama serve
32
+ ollama pull qwen2.5:7b
33
+
34
+ # Run a task
35
+ localist --task "Create a file called hello.txt with today's date, then list the workspace"
36
+ ```
37
+
38
+ ---
39
+
40
+ ## Installation
41
+
42
+ ```bash
43
+ # Core library + CLI
44
+ pip install localist
45
+
46
+ # With web UI (FastAPI + Uvicorn)
47
+ pip install "localist[ui]"
48
+
49
+ # Development
50
+ pip install "localist[dev]"
51
+ ```
52
+
53
+ ---
54
+
55
+ ## Usage
56
+
57
+ ### Python API
58
+
59
+ ```python
60
+ from localist import Agent
61
+
62
+ agent = Agent(model="qwen2.5:7b", workspace_root="./workspace")
63
+ result = agent.run("Search for the latest Python release and save a summary to workspace/python_news.txt")
64
+ print(result)
65
+ ```
66
+
67
+ ### Streaming events
68
+
69
+ ```python
70
+ from localist import Agent
71
+ from localist.agent import ToolCallEvent, FinalAnswerEvent
72
+
73
+ agent = Agent(model="qwen2.5:7b")
74
+
75
+ for event in agent.stream("Summarise all .txt files in workspace"):
76
+ if isinstance(event, ToolCallEvent):
77
+ print(f" 🔧 Calling: {event.tool}({event.args})")
78
+ elif isinstance(event, FinalAnswerEvent):
79
+ print(f"\n✅ Answer:\n{event.content}")
80
+ ```
81
+
82
+ ### Custom tools
83
+
84
+ ```python
85
+ from localist import Agent, register_tool
86
+
87
+ @register_tool
88
+ def count_words(text: str) -> int:
89
+ """Count the number of words in a text string.
90
+
91
+ Args:
92
+ text: The input text to count words in.
93
+ """
94
+ return len(text.split())
95
+
96
+ agent = Agent(model="qwen2.5:7b")
97
+ result = agent.run("Count the words in 'The quick brown fox jumps over the lazy dog'")
98
+ ```
99
+
100
+ ### CLI
101
+
102
+ ```bash
103
+ # Single task
104
+ localist --task "Create a Python script that generates the Fibonacci sequence"
105
+
106
+ # Custom model and workspace
107
+ localist --task "..." --model llama3.1:8b --workspace ~/myproject
108
+
109
+ # Interactive REPL
110
+ localist --interactive
111
+
112
+ # Web UI (requires pip install localist[ui])
113
+ localist --ui
114
+
115
+ # List available Ollama models
116
+ localist --list-models
117
+
118
+ # Disable confirmation prompts (for scripts/automation)
119
+ localist --task "..." --no-confirm
120
+ ```
121
+
122
+ ---
123
+
124
+ ## Tools
125
+
126
+ | Tool | Description | Confirmation required? |
127
+ |---|---|---|
128
+ | `file_read` | Read file contents | No |
129
+ | `file_write` | Create/overwrite a file | No (overwrite) |
130
+ | `file_append` | Append to a file | No |
131
+ | `file_delete` | Delete a file | **Yes** |
132
+ | `list_dir` | List directory contents | No |
133
+ | `web_search` | Search web (DuckDuckGo / Brave) | No |
134
+ | `web_fetch` | Fetch and extract text from URL | No |
135
+ | `shell_exec` | Run a shell command | **Yes** |
136
+ | `clipboard_get` | Read clipboard | No |
137
+ | `clipboard_set` | Write clipboard | No |
138
+ | `notify` | OS desktop notification | No |
139
+ | `process_list` | List running processes | No |
140
+ | `process_kill` | Terminate a process by PID | **Yes** |
141
+
142
+ ---
143
+
144
+ ## Configuration
145
+
146
+ Copy `.env.example` to `.env` and edit:
147
+
148
+ ```env
149
+ LOCALIST_MODEL=qwen2.5:7b
150
+ LOCALIST_WORKSPACE_ROOT=./workspace
151
+ LOCALIST_MAX_ITERATIONS=20
152
+ LOCALIST_REQUIRE_CONFIRMATION=true
153
+ BRAVE_API_KEY= # optional — enables Brave Search API
154
+ ```
155
+
156
+ All settings can also be passed programmatically:
157
+
158
+ ```python
159
+ from localist.config import LocalistConfig
160
+ from localist import Agent
161
+
162
+ cfg = LocalistConfig(model="llama3.1:8b", max_iterations=10, require_confirmation=False)
163
+ agent = Agent(config=cfg)
164
+ ```
165
+
166
+ ---
167
+
168
+ ## Safety
169
+
170
+ - **Filesystem jail**: every path is resolved against `workspace_root`; `..` traversal, symlink escapes, and absolute paths outside the workspace are rejected with `SandboxViolationError`.
171
+ - **Shell denylist**: `shell_exec` blocks `rm`, `sudo`, `curl`, `python`, shell interpreters, and other high-risk binaries. No `shell=True` anywhere.
172
+ - **Confirmation gate**: `file_delete`, `shell_exec`, and `process_kill` require explicit human approval (configurable).
173
+ - **Hard iteration cap**: the loop stops after `max_iterations` (default: 20) to prevent infinite loops.
174
+ - **Audit logging**: every tool call, result, and confirmation is written to `logs/audit_<date>.jsonl`.
175
+
176
+ ---
177
+
178
+ ## Model Recommendations
179
+
180
+ | Model | Tool-calling | Notes |
181
+ |---|---|---|
182
+ | `qwen2.5:7b` / `qwen2.5:32b` | Native | Best balance of speed and reliability |
183
+ | `llama3.1:8b` / `llama3.3:70b` | Native | Strong general reasoning |
184
+ | `hermes3` | Native | Optimised for agentic tasks |
185
+ | `mistral-nemo` | Native | Fast, solid tool support |
186
+ | Any other model | Text protocol | Automatic fallback with JSON repair |
187
+
188
+ ---
189
+
190
+ ## Build and Publish
191
+
192
+ ```bash
193
+ # Install build tools
194
+ pip install build twine
195
+
196
+ # Build
197
+ python -m build
198
+
199
+ # Validate
200
+ twine check dist/*
201
+
202
+ # Upload to TestPyPI
203
+ twine upload --repository testpypi dist/*
204
+
205
+ # Upload to PyPI
206
+ twine upload dist/*
207
+ ```
208
+
209
+ ---
210
+
211
+ ## Development
212
+
213
+ ```bash
214
+ git clone https://github.com/placeholder/localist
215
+ cd localist
216
+ pip install -e ".[dev]"
217
+ pytest tests/ -v
218
+ ```
219
+
220
+ ---
221
+
222
+ ## License
223
+
224
+ MIT — see [LICENSE](LICENSE).