quark-ai 0.1.1__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.
- quark_ai-0.1.1/.env.example +3 -0
- quark_ai-0.1.1/.github/workflows/publish.yml +36 -0
- quark_ai-0.1.1/.github/workflows/tests.yml +19 -0
- quark_ai-0.1.1/.gitignore +218 -0
- quark_ai-0.1.1/LICENSE +21 -0
- quark_ai-0.1.1/PKG-INFO +187 -0
- quark_ai-0.1.1/README.md +162 -0
- quark_ai-0.1.1/install.sh +49 -0
- quark_ai-0.1.1/pyproject.toml +42 -0
- quark_ai-0.1.1/quark/__init__.py +1 -0
- quark_ai-0.1.1/quark/__main__.py +6 -0
- quark_ai-0.1.1/quark/agent.py +53 -0
- quark_ai-0.1.1/quark/cli.py +164 -0
- quark_ai-0.1.1/quark/config.py +71 -0
- quark_ai-0.1.1/quark/message.py +34 -0
- quark_ai-0.1.1/quark/providers/__init__.py +19 -0
- quark_ai-0.1.1/quark/providers/anthropic.py +91 -0
- quark_ai-0.1.1/quark/providers/base.py +26 -0
- quark_ai-0.1.1/quark/providers/openai.py +81 -0
- quark_ai-0.1.1/quark/session.py +40 -0
- quark_ai-0.1.1/quark/tools/__init__.py +62 -0
- quark_ai-0.1.1/quark/tools/base.py +53 -0
- quark_ai-0.1.1/quark/tools/fs.py +144 -0
- quark_ai-0.1.1/quark/tools/meta.py +26 -0
- quark_ai-0.1.1/quark/tools/shell.py +41 -0
- quark_ai-0.1.1/quark/tools/workspace.py +24 -0
- quark_ai-0.1.1/tests/test_agent.py +115 -0
- quark_ai-0.1.1/tests/test_config.py +72 -0
- quark_ai-0.1.1/tests/test_message.py +24 -0
- quark_ai-0.1.1/tests/test_providers.py +118 -0
- quark_ai-0.1.1/tests/test_session.py +35 -0
- quark_ai-0.1.1/tests/test_tools.py +196 -0
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
name: Publish to PyPI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
release:
|
|
5
|
+
types: [published]
|
|
6
|
+
push:
|
|
7
|
+
tags:
|
|
8
|
+
- "v*"
|
|
9
|
+
|
|
10
|
+
jobs:
|
|
11
|
+
build:
|
|
12
|
+
runs-on: ubuntu-latest
|
|
13
|
+
steps:
|
|
14
|
+
- uses: actions/checkout@v4
|
|
15
|
+
- uses: actions/setup-python@v5
|
|
16
|
+
with:
|
|
17
|
+
python-version: "3.12"
|
|
18
|
+
- run: pip install build
|
|
19
|
+
- run: python -m build
|
|
20
|
+
- uses: actions/upload-artifact@v4
|
|
21
|
+
with:
|
|
22
|
+
name: dist
|
|
23
|
+
path: dist/
|
|
24
|
+
|
|
25
|
+
publish:
|
|
26
|
+
needs: build
|
|
27
|
+
runs-on: ubuntu-latest
|
|
28
|
+
environment: pypi
|
|
29
|
+
permissions:
|
|
30
|
+
id-token: write # required for PyPI Trusted Publishing (OIDC), no stored secrets
|
|
31
|
+
steps:
|
|
32
|
+
- uses: actions/download-artifact@v4
|
|
33
|
+
with:
|
|
34
|
+
name: dist
|
|
35
|
+
path: dist/
|
|
36
|
+
- uses: pypa/gh-action-pypi-publish@release/v1
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
name: Tests
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
pull_request:
|
|
6
|
+
|
|
7
|
+
jobs:
|
|
8
|
+
test:
|
|
9
|
+
runs-on: ubuntu-latest
|
|
10
|
+
strategy:
|
|
11
|
+
matrix:
|
|
12
|
+
python-version: ["3.10", "3.11", "3.12"]
|
|
13
|
+
steps:
|
|
14
|
+
- uses: actions/checkout@v4
|
|
15
|
+
- uses: actions/setup-python@v5
|
|
16
|
+
with:
|
|
17
|
+
python-version: ${{ matrix.python-version }}
|
|
18
|
+
- run: pip install -e ".[dev]"
|
|
19
|
+
- run: pytest -q
|
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
# Byte-compiled / optimized / DLL files
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[codz]
|
|
4
|
+
*$py.class
|
|
5
|
+
|
|
6
|
+
# C extensions
|
|
7
|
+
*.so
|
|
8
|
+
|
|
9
|
+
# Distribution / packaging
|
|
10
|
+
.Python
|
|
11
|
+
build/
|
|
12
|
+
develop-eggs/
|
|
13
|
+
dist/
|
|
14
|
+
downloads/
|
|
15
|
+
eggs/
|
|
16
|
+
.eggs/
|
|
17
|
+
lib/
|
|
18
|
+
lib64/
|
|
19
|
+
parts/
|
|
20
|
+
sdist/
|
|
21
|
+
var/
|
|
22
|
+
wheels/
|
|
23
|
+
share/python-wheels/
|
|
24
|
+
*.egg-info/
|
|
25
|
+
.installed.cfg
|
|
26
|
+
*.egg
|
|
27
|
+
MANIFEST
|
|
28
|
+
|
|
29
|
+
# PyInstaller
|
|
30
|
+
# Usually these files are written by a python script from a template
|
|
31
|
+
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
|
32
|
+
*.manifest
|
|
33
|
+
*.spec
|
|
34
|
+
|
|
35
|
+
# Installer logs
|
|
36
|
+
pip-log.txt
|
|
37
|
+
pip-delete-this-directory.txt
|
|
38
|
+
|
|
39
|
+
# Unit test / coverage reports
|
|
40
|
+
htmlcov/
|
|
41
|
+
.tox/
|
|
42
|
+
.nox/
|
|
43
|
+
.coverage
|
|
44
|
+
.coverage.*
|
|
45
|
+
.cache
|
|
46
|
+
nosetests.xml
|
|
47
|
+
coverage.xml
|
|
48
|
+
*.cover
|
|
49
|
+
*.py.cover
|
|
50
|
+
.hypothesis/
|
|
51
|
+
.pytest_cache/
|
|
52
|
+
cover/
|
|
53
|
+
|
|
54
|
+
# Translations
|
|
55
|
+
*.mo
|
|
56
|
+
*.pot
|
|
57
|
+
|
|
58
|
+
# Django stuff:
|
|
59
|
+
*.log
|
|
60
|
+
local_settings.py
|
|
61
|
+
db.sqlite3
|
|
62
|
+
db.sqlite3-journal
|
|
63
|
+
|
|
64
|
+
# Flask stuff:
|
|
65
|
+
instance/
|
|
66
|
+
.webassets-cache
|
|
67
|
+
|
|
68
|
+
# Scrapy stuff:
|
|
69
|
+
.scrapy
|
|
70
|
+
|
|
71
|
+
# Sphinx documentation
|
|
72
|
+
docs/_build/
|
|
73
|
+
|
|
74
|
+
# PyBuilder
|
|
75
|
+
.pybuilder/
|
|
76
|
+
target/
|
|
77
|
+
|
|
78
|
+
# Jupyter Notebook
|
|
79
|
+
.ipynb_checkpoints
|
|
80
|
+
|
|
81
|
+
# IPython
|
|
82
|
+
profile_default/
|
|
83
|
+
ipython_config.py
|
|
84
|
+
|
|
85
|
+
# pyenv
|
|
86
|
+
# For a library or package, you might want to ignore these files since the code is
|
|
87
|
+
# intended to run in multiple environments; otherwise, check them in:
|
|
88
|
+
# .python-version
|
|
89
|
+
|
|
90
|
+
# pipenv
|
|
91
|
+
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
|
|
92
|
+
# However, in case of collaboration, if having platform-specific dependencies or dependencies
|
|
93
|
+
# having no cross-platform support, pipenv may install dependencies that don't work, or not
|
|
94
|
+
# install all needed dependencies.
|
|
95
|
+
# Pipfile.lock
|
|
96
|
+
|
|
97
|
+
# UV
|
|
98
|
+
# Similar to Pipfile.lock, it is generally recommended to include uv.lock in version control.
|
|
99
|
+
# This is especially recommended for binary packages to ensure reproducibility, and is more
|
|
100
|
+
# commonly ignored for libraries.
|
|
101
|
+
# uv.lock
|
|
102
|
+
|
|
103
|
+
# poetry
|
|
104
|
+
# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
|
|
105
|
+
# This is especially recommended for binary packages to ensure reproducibility, and is more
|
|
106
|
+
# commonly ignored for libraries.
|
|
107
|
+
# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
|
|
108
|
+
# poetry.lock
|
|
109
|
+
# poetry.toml
|
|
110
|
+
|
|
111
|
+
# pdm
|
|
112
|
+
# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
|
|
113
|
+
# pdm recommends including project-wide configuration in pdm.toml, but excluding .pdm-python.
|
|
114
|
+
# https://pdm-project.org/en/latest/usage/project/#working-with-version-control
|
|
115
|
+
# pdm.lock
|
|
116
|
+
# pdm.toml
|
|
117
|
+
.pdm-python
|
|
118
|
+
.pdm-build/
|
|
119
|
+
|
|
120
|
+
# pixi
|
|
121
|
+
# Similar to Pipfile.lock, it is generally recommended to include pixi.lock in version control.
|
|
122
|
+
# pixi.lock
|
|
123
|
+
# Pixi creates a virtual environment in the .pixi directory, just like venv module creates one
|
|
124
|
+
# in the .venv directory. It is recommended not to include this directory in version control.
|
|
125
|
+
.pixi
|
|
126
|
+
|
|
127
|
+
# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
|
|
128
|
+
__pypackages__/
|
|
129
|
+
|
|
130
|
+
# Celery stuff
|
|
131
|
+
celerybeat-schedule
|
|
132
|
+
celerybeat.pid
|
|
133
|
+
|
|
134
|
+
# Redis
|
|
135
|
+
*.rdb
|
|
136
|
+
*.aof
|
|
137
|
+
*.pid
|
|
138
|
+
|
|
139
|
+
# RabbitMQ
|
|
140
|
+
mnesia/
|
|
141
|
+
rabbitmq/
|
|
142
|
+
rabbitmq-data/
|
|
143
|
+
|
|
144
|
+
# ActiveMQ
|
|
145
|
+
activemq-data/
|
|
146
|
+
|
|
147
|
+
# SageMath parsed files
|
|
148
|
+
*.sage.py
|
|
149
|
+
|
|
150
|
+
# Environments
|
|
151
|
+
.env
|
|
152
|
+
.envrc
|
|
153
|
+
.venv
|
|
154
|
+
env/
|
|
155
|
+
venv/
|
|
156
|
+
ENV/
|
|
157
|
+
env.bak/
|
|
158
|
+
venv.bak/
|
|
159
|
+
|
|
160
|
+
# Spyder project settings
|
|
161
|
+
.spyderproject
|
|
162
|
+
.spyproject
|
|
163
|
+
|
|
164
|
+
# Rope project settings
|
|
165
|
+
.ropeproject
|
|
166
|
+
|
|
167
|
+
# mkdocs documentation
|
|
168
|
+
/site
|
|
169
|
+
|
|
170
|
+
# mypy
|
|
171
|
+
.mypy_cache/
|
|
172
|
+
.dmypy.json
|
|
173
|
+
dmypy.json
|
|
174
|
+
|
|
175
|
+
# Pyre type checker
|
|
176
|
+
.pyre/
|
|
177
|
+
|
|
178
|
+
# pytype static type analyzer
|
|
179
|
+
.pytype/
|
|
180
|
+
|
|
181
|
+
# Cython debug symbols
|
|
182
|
+
cython_debug/
|
|
183
|
+
|
|
184
|
+
# PyCharm
|
|
185
|
+
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
|
|
186
|
+
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
|
|
187
|
+
# and can be added to the global gitignore or merged into this file. For a more nuclear
|
|
188
|
+
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
|
|
189
|
+
# .idea/
|
|
190
|
+
|
|
191
|
+
# Abstra
|
|
192
|
+
# Abstra is an AI-powered process automation framework.
|
|
193
|
+
# Ignore directories containing user credentials, local state, and settings.
|
|
194
|
+
# Learn more at https://abstra.io/docs
|
|
195
|
+
.abstra/
|
|
196
|
+
|
|
197
|
+
# Visual Studio Code
|
|
198
|
+
# Visual Studio Code specific template is maintained in a separate VisualStudioCode.gitignore
|
|
199
|
+
# that can be found at https://github.com/github/gitignore/blob/main/Global/VisualStudioCode.gitignore
|
|
200
|
+
# and can be added to the global gitignore or merged into this file. However, if you prefer,
|
|
201
|
+
# you could uncomment the following to ignore the entire vscode folder
|
|
202
|
+
# .vscode/
|
|
203
|
+
# Temporary file for partial code execution
|
|
204
|
+
tempCodeRunnerFile.py
|
|
205
|
+
|
|
206
|
+
# Ruff stuff:
|
|
207
|
+
.ruff_cache/
|
|
208
|
+
|
|
209
|
+
# PyPI configuration file
|
|
210
|
+
.pypirc
|
|
211
|
+
|
|
212
|
+
# Marimo
|
|
213
|
+
marimo/_static/
|
|
214
|
+
marimo/_lsp/
|
|
215
|
+
__marimo__/
|
|
216
|
+
|
|
217
|
+
# Streamlit
|
|
218
|
+
.streamlit/secrets.toml
|
quark_ai-0.1.1/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Moyter
|
|
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.
|
quark_ai-0.1.1/PKG-INFO
ADDED
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: quark-ai
|
|
3
|
+
Version: 0.1.1
|
|
4
|
+
Summary: Lightning-fast micro-agent. A stripped-down alternative to heavy AI agents, executing tasks with minimal prompt overhead.
|
|
5
|
+
Project-URL: Homepage, https://github.com/rmoya81/Quark
|
|
6
|
+
Project-URL: Repository, https://github.com/rmoya81/Quark
|
|
7
|
+
Project-URL: Issues, https://github.com/rmoya81/Quark/issues
|
|
8
|
+
Author: rmoya81
|
|
9
|
+
License-Expression: MIT
|
|
10
|
+
License-File: LICENSE
|
|
11
|
+
Classifier: Development Status :: 3 - Alpha
|
|
12
|
+
Classifier: Environment :: Console
|
|
13
|
+
Classifier: Intended Audience :: Developers
|
|
14
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
15
|
+
Classifier: Programming Language :: Python :: 3
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
19
|
+
Classifier: Topic :: Software Development :: Libraries
|
|
20
|
+
Requires-Python: >=3.10
|
|
21
|
+
Requires-Dist: httpx>=0.27
|
|
22
|
+
Provides-Extra: dev
|
|
23
|
+
Requires-Dist: pytest>=8.0; extra == 'dev'
|
|
24
|
+
Description-Content-Type: text/markdown
|
|
25
|
+
|
|
26
|
+
# Quark
|
|
27
|
+
|
|
28
|
+
Lightning-fast micro-agent. A stripped-down alternative to heavy AI agents, executing tasks with minimal prompt overhead.
|
|
29
|
+
|
|
30
|
+
Quark is a minimal CLI agent loop: send a message, let the model call tools (read/edit/write files, list directories, optionally run shell commands), and get an answer back — with conversation history persisted to disk between runs. It talks to any LLM provider through a small abstraction layer (Anthropic and OpenAI included) instead of depending on a heavy vendor SDK.
|
|
31
|
+
|
|
32
|
+
Two things it optimizes for on purpose:
|
|
33
|
+
- **Lightweight**: no framework, no heavy SDKs (just `httpx`), a short default system prompt, and an `edit_file` tool so the model can make targeted changes instead of re-sending whole files.
|
|
34
|
+
- **Productive by default, secure by default**: file tools are confined to a workspace directory (symlink escapes included), `run_shell` is off unless you opt in, and if a `QUARK.md`/`AGENTS.md` file exists it's folded into the system prompt automatically so the agent already knows about your project.
|
|
35
|
+
|
|
36
|
+
## Install
|
|
37
|
+
|
|
38
|
+
Requires Python 3.10+. Works anywhere Python does, including WSL2 — nothing platform-specific.
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
./install.sh
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
Creates `.venv`, installs Quark editable with dev deps, and copies `.env.example` to `.env` if you don't already have one. Safe to re-run (reuses the venv, never overwrites an existing `.env`).
|
|
45
|
+
|
|
46
|
+
Or by hand:
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
python3 -m venv .venv
|
|
50
|
+
source .venv/bin/activate
|
|
51
|
+
pip install -e ".[dev]"
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
## Configure
|
|
55
|
+
|
|
56
|
+
Copy `.env.example` to `.env` (done automatically by `install.sh`) and fill in the key(s) for the provider(s) you want to use:
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
cp .env.example .env
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
```
|
|
63
|
+
ANTHROPIC_API_KEY=sk-ant-...
|
|
64
|
+
OPENAI_API_KEY=sk-...
|
|
65
|
+
QUARK_PROVIDER=anthropic
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
`.env` is loaded automatically from the current working directory. You can also export the variables directly, or pass `--api-key` on the command line.
|
|
69
|
+
|
|
70
|
+
## Usage
|
|
71
|
+
|
|
72
|
+
```bash
|
|
73
|
+
# One-shot message, prints the reply and exits
|
|
74
|
+
quark chat "list the files in this directory"
|
|
75
|
+
|
|
76
|
+
# Interactive REPL (Ctrl+D or 'exit' to quit)
|
|
77
|
+
quark chat
|
|
78
|
+
|
|
79
|
+
# Choose a provider/model
|
|
80
|
+
quark --provider openai --model gpt-4o chat "what's in README.md?"
|
|
81
|
+
|
|
82
|
+
# Named sessions keep separate histories on disk
|
|
83
|
+
quark --session project-a chat "remember that we're using Postgres"
|
|
84
|
+
quark --session project-a chat "what database are we using?"
|
|
85
|
+
|
|
86
|
+
# Confine file tools to a specific directory (default: cwd)
|
|
87
|
+
quark --workspace ./my-project chat "list the files here"
|
|
88
|
+
|
|
89
|
+
# Opt in to the run_shell tool (off by default)
|
|
90
|
+
quark --allow-shell chat "run the test suite"
|
|
91
|
+
|
|
92
|
+
# Read-only mode: only read_file + list_dir, smallest tool-schema footprint, no escape hatch
|
|
93
|
+
quark --minimal-tools chat "what does this project do?"
|
|
94
|
+
|
|
95
|
+
# Progressive mode: starts like --minimal-tools, but the model can unlock
|
|
96
|
+
# write_file/edit_file/delete_file itself the moment it actually needs them
|
|
97
|
+
quark --progressive-tools chat "fix the typo in README.md"
|
|
98
|
+
|
|
99
|
+
# Manage sessions
|
|
100
|
+
quark sessions list
|
|
101
|
+
quark sessions clear project-a
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
Sessions are stored as JSON under `~/.quark/sessions/<name>.json`.
|
|
105
|
+
|
|
106
|
+
### Project context
|
|
107
|
+
|
|
108
|
+
If a `QUARK.md` or `AGENTS.md` file exists at the workspace root, its contents are appended to the system prompt automatically — a cheap way to give the agent standing context (stack, conventions, gotchas) without repeating it every session.
|
|
109
|
+
|
|
110
|
+
### Progressive tool disclosure
|
|
111
|
+
|
|
112
|
+
`--progressive-tools` (also `QUARK_PROGRESSIVE_TOOLS=1`) starts a turn with just `read_file`, `list_dir`, and one cheap extra tool, `request_more_tools` (no parameters). Its description tells the model to call it if it needs to write, edit, or delete files. If the model calls it, Quark registers `write_file`/`edit_file`/`delete_file` on the spot, drops `request_more_tools` (no longer needed), and the *same* `agent.step()` call retries with the expanded set — so the model still gets everything it needs, in the same turn, it just asks first.
|
|
113
|
+
|
|
114
|
+
This is deliberately not a heuristic: matching intent from text (keywords, embeddings, a classifier) always trades accuracy for cost and can silently withhold a tool the model actually needed on some phrasing you didn't anticipate. Letting the model itself request more tools can't misfire that way — the only cost is one extra round trip, and only on turns that actually mutate something. `run_shell` stays independently gated behind `--allow-shell`; progressive mode never unlocks it.
|
|
115
|
+
|
|
116
|
+
`--minimal-tools` is the stricter sibling: same starting set, but with no `request_more_tools` escape hatch at all, for when you want a hard read-only guarantee. Passing both flags together, `--minimal-tools` wins.
|
|
117
|
+
|
|
118
|
+
### Token overhead
|
|
119
|
+
|
|
120
|
+
On the first turn (empty session), before the model generates anything, Quark sends the system prompt plus the JSON schema of every registered tool. Rough token counts (`tiktoken` `cl100k_base`, an approximation — Claude's real tokenizer isn't public — but the right order of magnitude either way):
|
|
121
|
+
|
|
122
|
+
| Mode | Tools registered | Tool-schema tokens | Total (system + tools + a short message) |
|
|
123
|
+
|---|---|---|---|
|
|
124
|
+
| default | `read_file`, `list_dir`, `write_file`, `edit_file`, `delete_file` | ~380 | ~415 |
|
|
125
|
+
| `--minimal-tools` | `read_file`, `list_dir` | ~120 | ~155 |
|
|
126
|
+
| `--progressive-tools`, before unlocking | `read_file`, `list_dir`, `request_more_tools` | ~165 | ~200 |
|
|
127
|
+
| `--progressive-tools`, after unlocking | same as default | ~380 | ~415 |
|
|
128
|
+
| default + `--allow-shell` | + `run_shell` | ~380 + ~65 | ~480 |
|
|
129
|
+
|
|
130
|
+
`--minimal-tools` is cheapest but can never write/edit/delete. `--progressive-tools` costs a little more than minimal on read-only turns (~200 vs ~155) but is capability-equivalent to the default the moment it's actually needed — it only pays the full ~415 on turns that mutate something. Every subsequent turn in a session also carries the accumulated conversation history on top of these numbers.
|
|
131
|
+
|
|
132
|
+
## Architecture
|
|
133
|
+
|
|
134
|
+
```
|
|
135
|
+
quark/
|
|
136
|
+
message.py Internal Message/ToolCall representation
|
|
137
|
+
session.py Persistent, named conversation history
|
|
138
|
+
agent.py The chat + tool-calling loop
|
|
139
|
+
providers/ Provider abstraction (unified request/response shape)
|
|
140
|
+
base.py
|
|
141
|
+
anthropic.py Anthropic Messages API
|
|
142
|
+
openai.py OpenAI Chat Completions API
|
|
143
|
+
tools/ Built-in tools the agent can call
|
|
144
|
+
base.py Tool + ToolRegistry
|
|
145
|
+
workspace.py Path confinement (resolve_within)
|
|
146
|
+
fs.py read_file / write_file / edit_file / delete_file / list_dir
|
|
147
|
+
shell.py run_shell (opt-in)
|
|
148
|
+
meta.py request_more_tools (--progressive-tools)
|
|
149
|
+
cli.py argparse-based entry point
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
Adding a provider means implementing `Provider.complete()` in `quark/providers/` and registering it in `quark/providers/__init__.py`. Adding a tool means subclassing `Tool` in `quark/tools/` and adding it to `default_registry()`.
|
|
153
|
+
|
|
154
|
+
## Security note
|
|
155
|
+
|
|
156
|
+
- `read_file`, `write_file`, `edit_file`, `delete_file`, and `list_dir` are confined to `--workspace` (default: the current directory); paths that escape it, including via symlinks, are rejected.
|
|
157
|
+
- `run_shell` executes arbitrary shell commands and is **off by default** — enable it with `--allow-shell` or `QUARK_ALLOW_SHELL=1` only when you trust the prompts/provider you're running against.
|
|
158
|
+
- `write_file` and `delete_file` still mutate the filesystem inside the workspace without asking for confirmation. Only point Quark at trusted providers/prompts, and run it in an environment you're comfortable with an autonomous agent touching.
|
|
159
|
+
|
|
160
|
+
## Roadmap / not yet implemented
|
|
161
|
+
|
|
162
|
+
- Streaming responses (print tokens as they arrive instead of waiting for the full reply).
|
|
163
|
+
- Automatic context compaction for long-running sessions that approach the model's context window.
|
|
164
|
+
|
|
165
|
+
## Development
|
|
166
|
+
|
|
167
|
+
```bash
|
|
168
|
+
pip install -e ".[dev]"
|
|
169
|
+
pytest
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
Tests mock the HTTP layer (`httpx.post`), so the suite runs offline with no API keys required.
|
|
173
|
+
|
|
174
|
+
## Publishing to PyPI
|
|
175
|
+
|
|
176
|
+
The project builds as `quark-ai` (the CLI command stays `quark` either way — the package name on PyPI doesn't have to match the command it installs). `.github/workflows/publish.yml` publishes to PyPI via [Trusted Publishing](https://docs.pypi.org/trusted-publishers/) (OIDC) whenever a GitHub Release is published — no API token stored in the repo.
|
|
177
|
+
|
|
178
|
+
One-time setup (done from your own PyPI account, not from CI):
|
|
179
|
+
|
|
180
|
+
1. Create a PyPI account at [pypi.org](https://pypi.org) if you don't have one, and enable 2FA (PyPI requires it).
|
|
181
|
+
2. Go to [pypi.org/manage/account/publishing](https://pypi.org/manage/account/publishing/) and add a **pending publisher**:
|
|
182
|
+
PyPI project name `quark-ai`, owner `rmoya81`, repository `Quark`, workflow `publish.yml`, environment `pypi`.
|
|
183
|
+
This reserves the name immediately — the project is created the moment the first publish succeeds, and only this repo's workflow can publish to it.
|
|
184
|
+
3. In the GitHub repo, create an environment named `pypi` (Settings → Environments), matching the one in the workflow and in the pending publisher config.
|
|
185
|
+
4. Cut a GitHub Release (tag `v0.1.0` or similar) — the workflow builds the sdist/wheel and publishes them automatically.
|
|
186
|
+
|
|
187
|
+
To claim the name immediately instead of waiting on that setup (e.g. to block squatting right now), a one-off manual publish works too: `pip install build twine && python -m build && twine upload dist/*` with a PyPI API token — `quark-ai`/`quark-cli`/`quarkagent`/`quark-micro-agent`/`quark-llm-agent` are all currently unregistered as of this writing; `quark` and `quark-agent` are already taken by unrelated projects.
|
quark_ai-0.1.1/README.md
ADDED
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
# Quark
|
|
2
|
+
|
|
3
|
+
Lightning-fast micro-agent. A stripped-down alternative to heavy AI agents, executing tasks with minimal prompt overhead.
|
|
4
|
+
|
|
5
|
+
Quark is a minimal CLI agent loop: send a message, let the model call tools (read/edit/write files, list directories, optionally run shell commands), and get an answer back — with conversation history persisted to disk between runs. It talks to any LLM provider through a small abstraction layer (Anthropic and OpenAI included) instead of depending on a heavy vendor SDK.
|
|
6
|
+
|
|
7
|
+
Two things it optimizes for on purpose:
|
|
8
|
+
- **Lightweight**: no framework, no heavy SDKs (just `httpx`), a short default system prompt, and an `edit_file` tool so the model can make targeted changes instead of re-sending whole files.
|
|
9
|
+
- **Productive by default, secure by default**: file tools are confined to a workspace directory (symlink escapes included), `run_shell` is off unless you opt in, and if a `QUARK.md`/`AGENTS.md` file exists it's folded into the system prompt automatically so the agent already knows about your project.
|
|
10
|
+
|
|
11
|
+
## Install
|
|
12
|
+
|
|
13
|
+
Requires Python 3.10+. Works anywhere Python does, including WSL2 — nothing platform-specific.
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
./install.sh
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
Creates `.venv`, installs Quark editable with dev deps, and copies `.env.example` to `.env` if you don't already have one. Safe to re-run (reuses the venv, never overwrites an existing `.env`).
|
|
20
|
+
|
|
21
|
+
Or by hand:
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
python3 -m venv .venv
|
|
25
|
+
source .venv/bin/activate
|
|
26
|
+
pip install -e ".[dev]"
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## Configure
|
|
30
|
+
|
|
31
|
+
Copy `.env.example` to `.env` (done automatically by `install.sh`) and fill in the key(s) for the provider(s) you want to use:
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
cp .env.example .env
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
```
|
|
38
|
+
ANTHROPIC_API_KEY=sk-ant-...
|
|
39
|
+
OPENAI_API_KEY=sk-...
|
|
40
|
+
QUARK_PROVIDER=anthropic
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
`.env` is loaded automatically from the current working directory. You can also export the variables directly, or pass `--api-key` on the command line.
|
|
44
|
+
|
|
45
|
+
## Usage
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
# One-shot message, prints the reply and exits
|
|
49
|
+
quark chat "list the files in this directory"
|
|
50
|
+
|
|
51
|
+
# Interactive REPL (Ctrl+D or 'exit' to quit)
|
|
52
|
+
quark chat
|
|
53
|
+
|
|
54
|
+
# Choose a provider/model
|
|
55
|
+
quark --provider openai --model gpt-4o chat "what's in README.md?"
|
|
56
|
+
|
|
57
|
+
# Named sessions keep separate histories on disk
|
|
58
|
+
quark --session project-a chat "remember that we're using Postgres"
|
|
59
|
+
quark --session project-a chat "what database are we using?"
|
|
60
|
+
|
|
61
|
+
# Confine file tools to a specific directory (default: cwd)
|
|
62
|
+
quark --workspace ./my-project chat "list the files here"
|
|
63
|
+
|
|
64
|
+
# Opt in to the run_shell tool (off by default)
|
|
65
|
+
quark --allow-shell chat "run the test suite"
|
|
66
|
+
|
|
67
|
+
# Read-only mode: only read_file + list_dir, smallest tool-schema footprint, no escape hatch
|
|
68
|
+
quark --minimal-tools chat "what does this project do?"
|
|
69
|
+
|
|
70
|
+
# Progressive mode: starts like --minimal-tools, but the model can unlock
|
|
71
|
+
# write_file/edit_file/delete_file itself the moment it actually needs them
|
|
72
|
+
quark --progressive-tools chat "fix the typo in README.md"
|
|
73
|
+
|
|
74
|
+
# Manage sessions
|
|
75
|
+
quark sessions list
|
|
76
|
+
quark sessions clear project-a
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
Sessions are stored as JSON under `~/.quark/sessions/<name>.json`.
|
|
80
|
+
|
|
81
|
+
### Project context
|
|
82
|
+
|
|
83
|
+
If a `QUARK.md` or `AGENTS.md` file exists at the workspace root, its contents are appended to the system prompt automatically — a cheap way to give the agent standing context (stack, conventions, gotchas) without repeating it every session.
|
|
84
|
+
|
|
85
|
+
### Progressive tool disclosure
|
|
86
|
+
|
|
87
|
+
`--progressive-tools` (also `QUARK_PROGRESSIVE_TOOLS=1`) starts a turn with just `read_file`, `list_dir`, and one cheap extra tool, `request_more_tools` (no parameters). Its description tells the model to call it if it needs to write, edit, or delete files. If the model calls it, Quark registers `write_file`/`edit_file`/`delete_file` on the spot, drops `request_more_tools` (no longer needed), and the *same* `agent.step()` call retries with the expanded set — so the model still gets everything it needs, in the same turn, it just asks first.
|
|
88
|
+
|
|
89
|
+
This is deliberately not a heuristic: matching intent from text (keywords, embeddings, a classifier) always trades accuracy for cost and can silently withhold a tool the model actually needed on some phrasing you didn't anticipate. Letting the model itself request more tools can't misfire that way — the only cost is one extra round trip, and only on turns that actually mutate something. `run_shell` stays independently gated behind `--allow-shell`; progressive mode never unlocks it.
|
|
90
|
+
|
|
91
|
+
`--minimal-tools` is the stricter sibling: same starting set, but with no `request_more_tools` escape hatch at all, for when you want a hard read-only guarantee. Passing both flags together, `--minimal-tools` wins.
|
|
92
|
+
|
|
93
|
+
### Token overhead
|
|
94
|
+
|
|
95
|
+
On the first turn (empty session), before the model generates anything, Quark sends the system prompt plus the JSON schema of every registered tool. Rough token counts (`tiktoken` `cl100k_base`, an approximation — Claude's real tokenizer isn't public — but the right order of magnitude either way):
|
|
96
|
+
|
|
97
|
+
| Mode | Tools registered | Tool-schema tokens | Total (system + tools + a short message) |
|
|
98
|
+
|---|---|---|---|
|
|
99
|
+
| default | `read_file`, `list_dir`, `write_file`, `edit_file`, `delete_file` | ~380 | ~415 |
|
|
100
|
+
| `--minimal-tools` | `read_file`, `list_dir` | ~120 | ~155 |
|
|
101
|
+
| `--progressive-tools`, before unlocking | `read_file`, `list_dir`, `request_more_tools` | ~165 | ~200 |
|
|
102
|
+
| `--progressive-tools`, after unlocking | same as default | ~380 | ~415 |
|
|
103
|
+
| default + `--allow-shell` | + `run_shell` | ~380 + ~65 | ~480 |
|
|
104
|
+
|
|
105
|
+
`--minimal-tools` is cheapest but can never write/edit/delete. `--progressive-tools` costs a little more than minimal on read-only turns (~200 vs ~155) but is capability-equivalent to the default the moment it's actually needed — it only pays the full ~415 on turns that mutate something. Every subsequent turn in a session also carries the accumulated conversation history on top of these numbers.
|
|
106
|
+
|
|
107
|
+
## Architecture
|
|
108
|
+
|
|
109
|
+
```
|
|
110
|
+
quark/
|
|
111
|
+
message.py Internal Message/ToolCall representation
|
|
112
|
+
session.py Persistent, named conversation history
|
|
113
|
+
agent.py The chat + tool-calling loop
|
|
114
|
+
providers/ Provider abstraction (unified request/response shape)
|
|
115
|
+
base.py
|
|
116
|
+
anthropic.py Anthropic Messages API
|
|
117
|
+
openai.py OpenAI Chat Completions API
|
|
118
|
+
tools/ Built-in tools the agent can call
|
|
119
|
+
base.py Tool + ToolRegistry
|
|
120
|
+
workspace.py Path confinement (resolve_within)
|
|
121
|
+
fs.py read_file / write_file / edit_file / delete_file / list_dir
|
|
122
|
+
shell.py run_shell (opt-in)
|
|
123
|
+
meta.py request_more_tools (--progressive-tools)
|
|
124
|
+
cli.py argparse-based entry point
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
Adding a provider means implementing `Provider.complete()` in `quark/providers/` and registering it in `quark/providers/__init__.py`. Adding a tool means subclassing `Tool` in `quark/tools/` and adding it to `default_registry()`.
|
|
128
|
+
|
|
129
|
+
## Security note
|
|
130
|
+
|
|
131
|
+
- `read_file`, `write_file`, `edit_file`, `delete_file`, and `list_dir` are confined to `--workspace` (default: the current directory); paths that escape it, including via symlinks, are rejected.
|
|
132
|
+
- `run_shell` executes arbitrary shell commands and is **off by default** — enable it with `--allow-shell` or `QUARK_ALLOW_SHELL=1` only when you trust the prompts/provider you're running against.
|
|
133
|
+
- `write_file` and `delete_file` still mutate the filesystem inside the workspace without asking for confirmation. Only point Quark at trusted providers/prompts, and run it in an environment you're comfortable with an autonomous agent touching.
|
|
134
|
+
|
|
135
|
+
## Roadmap / not yet implemented
|
|
136
|
+
|
|
137
|
+
- Streaming responses (print tokens as they arrive instead of waiting for the full reply).
|
|
138
|
+
- Automatic context compaction for long-running sessions that approach the model's context window.
|
|
139
|
+
|
|
140
|
+
## Development
|
|
141
|
+
|
|
142
|
+
```bash
|
|
143
|
+
pip install -e ".[dev]"
|
|
144
|
+
pytest
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
Tests mock the HTTP layer (`httpx.post`), so the suite runs offline with no API keys required.
|
|
148
|
+
|
|
149
|
+
## Publishing to PyPI
|
|
150
|
+
|
|
151
|
+
The project builds as `quark-ai` (the CLI command stays `quark` either way — the package name on PyPI doesn't have to match the command it installs). `.github/workflows/publish.yml` publishes to PyPI via [Trusted Publishing](https://docs.pypi.org/trusted-publishers/) (OIDC) whenever a GitHub Release is published — no API token stored in the repo.
|
|
152
|
+
|
|
153
|
+
One-time setup (done from your own PyPI account, not from CI):
|
|
154
|
+
|
|
155
|
+
1. Create a PyPI account at [pypi.org](https://pypi.org) if you don't have one, and enable 2FA (PyPI requires it).
|
|
156
|
+
2. Go to [pypi.org/manage/account/publishing](https://pypi.org/manage/account/publishing/) and add a **pending publisher**:
|
|
157
|
+
PyPI project name `quark-ai`, owner `rmoya81`, repository `Quark`, workflow `publish.yml`, environment `pypi`.
|
|
158
|
+
This reserves the name immediately — the project is created the moment the first publish succeeds, and only this repo's workflow can publish to it.
|
|
159
|
+
3. In the GitHub repo, create an environment named `pypi` (Settings → Environments), matching the one in the workflow and in the pending publisher config.
|
|
160
|
+
4. Cut a GitHub Release (tag `v0.1.0` or similar) — the workflow builds the sdist/wheel and publishes them automatically.
|
|
161
|
+
|
|
162
|
+
To claim the name immediately instead of waiting on that setup (e.g. to block squatting right now), a one-off manual publish works too: `pip install build twine && python -m build && twine upload dist/*` with a PyPI API token — `quark-ai`/`quark-cli`/`quarkagent`/`quark-micro-agent`/`quark-llm-agent` are all currently unregistered as of this writing; `quark` and `quark-agent` are already taken by unrelated projects.
|