kartikeya 0.0.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.
@@ -0,0 +1,55 @@
1
+ name: Release
2
+
3
+ # Publishes to PyPI when a version tag is pushed (e.g. `git tag v0.0.1 && git push --tags`).
4
+ #
5
+ # Auth: a PyPI API token stored as the repo Actions secret `PYPI_API_TOKEN`
6
+ # (Settings -> Secrets and variables -> Actions). One-time setup: create the
7
+ # token on PyPI and add that secret. Until it exists, the publish step fails.
8
+ # (Trusted Publishing / OIDC is the tokenless alternative but this project uses
9
+ # the token pattern for parity with the operator's other releases.)
10
+
11
+ on:
12
+ push:
13
+ tags:
14
+ - "v*"
15
+
16
+ jobs:
17
+ build:
18
+ runs-on: ubuntu-latest
19
+ steps:
20
+ - uses: actions/checkout@v4
21
+
22
+ - uses: actions/setup-python@v5
23
+ with:
24
+ python-version: "3.11"
25
+
26
+ - name: Build sdist and wheel
27
+ run: |
28
+ python -m pip install --upgrade build
29
+ python -m build
30
+
31
+ - name: Check metadata
32
+ run: |
33
+ python -m pip install --upgrade twine
34
+ twine check dist/*
35
+
36
+ - uses: actions/upload-artifact@v4
37
+ with:
38
+ name: dist
39
+ path: dist/
40
+
41
+ publish:
42
+ needs: build
43
+ runs-on: ubuntu-latest
44
+ environment: pypi
45
+ steps:
46
+ - uses: actions/download-artifact@v4
47
+ with:
48
+ name: dist
49
+ path: dist/
50
+
51
+ - name: Publish to PyPI
52
+ uses: pypa/gh-action-pypi-publish@release/v1
53
+ with:
54
+ password: ${{ secrets.PYPI_API_TOKEN }}
55
+ attestations: false # attestations require OIDC/Trusted Publishing
@@ -0,0 +1,29 @@
1
+ name: Tests
2
+
3
+ on:
4
+ push:
5
+ branches: ["master", "main"]
6
+ pull_request:
7
+ branches: ["master", "main"]
8
+
9
+ jobs:
10
+ test:
11
+ runs-on: ubuntu-latest
12
+ strategy:
13
+ matrix:
14
+ python-version: ["3.11", "3.12", "3.13"]
15
+ steps:
16
+ - uses: actions/checkout@v4
17
+
18
+ - uses: actions/setup-python@v5
19
+ with:
20
+ python-version: ${{ matrix.python-version }}
21
+
22
+ - name: Install bubblewrap
23
+ run: sudo apt-get update && sudo apt-get install -y bubblewrap
24
+
25
+ - name: Install
26
+ run: pip install -e "." pytest
27
+
28
+ - name: Run tests
29
+ run: python -m pytest tests/ -q
@@ -0,0 +1,15 @@
1
+ __pycache__/
2
+ *.py[cod]
3
+ *.egg-info/
4
+ .eggs/
5
+ build/
6
+ dist/
7
+ .venv/
8
+ venv/
9
+ .pytest_cache/
10
+ .ruff_cache/
11
+ *.db
12
+ *.sqlite
13
+ *.sqlite3
14
+ .kart-scripts/
15
+ .DS_Store
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Sean Campbell
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,79 @@
1
+ Metadata-Version: 2.4
2
+ Name: kartikeya
3
+ Version: 0.0.1
4
+ Summary: Kartikeya — a standalone bubblewrap-sandboxed task queue and worker. Backend-agnostic (SQLite or Postgres); the execution engine formerly known as Kart.
5
+ Project-URL: Homepage, https://github.com/rudi193-cmd/kartikeya
6
+ Project-URL: Repository, https://github.com/rudi193-cmd/kartikeya
7
+ Project-URL: Issues, https://github.com/rudi193-cmd/kartikeya/issues
8
+ Author: Sean Campbell
9
+ License: MIT
10
+ License-File: LICENSE
11
+ Keywords: bubblewrap,bwrap,kart,sandbox,task-queue,willow,worker
12
+ Classifier: Development Status :: 3 - Alpha
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: License :: OSI Approved :: MIT License
15
+ Classifier: Operating System :: POSIX :: Linux
16
+ Classifier: Programming Language :: Python :: 3
17
+ Classifier: Programming Language :: Python :: 3.11
18
+ Classifier: Programming Language :: Python :: 3.12
19
+ Classifier: Programming Language :: Python :: 3.13
20
+ Classifier: Topic :: Software Development :: Libraries
21
+ Classifier: Topic :: System :: Distributed Computing
22
+ Requires-Python: >=3.11
23
+ Provides-Extra: llm
24
+ Provides-Extra: postgres
25
+ Requires-Dist: psycopg2-binary<3.0,>=2.9; extra == 'postgres'
26
+ Description-Content-Type: text/markdown
27
+
28
+ # Kartikeya
29
+
30
+ > Skanda · Murugan — the six-faced commander of the divine armies, born to lead
31
+ > the devas. The engine that marshals and runs a fleet's tasks. Colloquially:
32
+ > **Kart**.
33
+
34
+ A standalone, host-agnostic **task queue + sandboxed worker**. Submit shell (or,
35
+ optionally, LLM-workflow) tasks to a queue; a worker claims them and runs each in
36
+ a [bubblewrap](https://github.com/containers/bubblewrap) sandbox with an explicit
37
+ mount/credential/network policy.
38
+
39
+ Kartikeya is the execution engine extracted from the Willow fleet
40
+ (`willow-2.0/core/kart_*`) and made to stand on its own — no fleet, no specific
41
+ host, no required database server.
42
+
43
+ ## Status
44
+
45
+ **Pre-alpha, under active extraction.** This repo is the target of a staged lift
46
+ described in `docs/DESIGN.md`. The scaffold and the `TaskQueue` interface are in
47
+ place; the sandbox/worker/execute core is being decoupled from its origin and
48
+ brought over next.
49
+
50
+ ## Design goals
51
+
52
+ - **Host-agnostic.** The only coupling — "where do tasks live" — is a small
53
+ `TaskQueue` interface a host implements. Kartikeya owns the sandbox, worker
54
+ loop, lanes, and command scan; the host owns storage and file roots.
55
+ - **Zero-infra by default.** Ships a reference `SqliteTaskQueue`, so
56
+ `pip install kartikeya` can execute tasks with no Postgres and no fleet.
57
+ - **Backend-swappable.** SQLite (bundled), Postgres, or a custom backend behind
58
+ the same interface.
59
+ - **Sandboxed and network-gated.** Tasks run network-isolated unless the stored
60
+ task text carries a `# allow_net` directive; credentials reach only network-
61
+ enabled tasks. (Who is allowed to *write* that directive is the host's call —
62
+ see the security note in `docs/DESIGN.md`.)
63
+
64
+ ## Install
65
+
66
+ ```
67
+ pip install kartikeya # base: shell tasks, SQLite backend
68
+ pip install "kartikeya[postgres]" # + Postgres backend helpers
69
+ pip install "kartikeya[llm]" # + LLM-workflow task type
70
+ ```
71
+
72
+ ## Quickstart
73
+
74
+ _Coming with stage 2 — once the worker core lands, this section documents
75
+ `kartikeya worker` end to end (submit → worker runs → poll)._
76
+
77
+ ## License
78
+
79
+ MIT © Sean Campbell
@@ -0,0 +1,52 @@
1
+ # Kartikeya
2
+
3
+ > Skanda · Murugan — the six-faced commander of the divine armies, born to lead
4
+ > the devas. The engine that marshals and runs a fleet's tasks. Colloquially:
5
+ > **Kart**.
6
+
7
+ A standalone, host-agnostic **task queue + sandboxed worker**. Submit shell (or,
8
+ optionally, LLM-workflow) tasks to a queue; a worker claims them and runs each in
9
+ a [bubblewrap](https://github.com/containers/bubblewrap) sandbox with an explicit
10
+ mount/credential/network policy.
11
+
12
+ Kartikeya is the execution engine extracted from the Willow fleet
13
+ (`willow-2.0/core/kart_*`) and made to stand on its own — no fleet, no specific
14
+ host, no required database server.
15
+
16
+ ## Status
17
+
18
+ **Pre-alpha, under active extraction.** This repo is the target of a staged lift
19
+ described in `docs/DESIGN.md`. The scaffold and the `TaskQueue` interface are in
20
+ place; the sandbox/worker/execute core is being decoupled from its origin and
21
+ brought over next.
22
+
23
+ ## Design goals
24
+
25
+ - **Host-agnostic.** The only coupling — "where do tasks live" — is a small
26
+ `TaskQueue` interface a host implements. Kartikeya owns the sandbox, worker
27
+ loop, lanes, and command scan; the host owns storage and file roots.
28
+ - **Zero-infra by default.** Ships a reference `SqliteTaskQueue`, so
29
+ `pip install kartikeya` can execute tasks with no Postgres and no fleet.
30
+ - **Backend-swappable.** SQLite (bundled), Postgres, or a custom backend behind
31
+ the same interface.
32
+ - **Sandboxed and network-gated.** Tasks run network-isolated unless the stored
33
+ task text carries a `# allow_net` directive; credentials reach only network-
34
+ enabled tasks. (Who is allowed to *write* that directive is the host's call —
35
+ see the security note in `docs/DESIGN.md`.)
36
+
37
+ ## Install
38
+
39
+ ```
40
+ pip install kartikeya # base: shell tasks, SQLite backend
41
+ pip install "kartikeya[postgres]" # + Postgres backend helpers
42
+ pip install "kartikeya[llm]" # + LLM-workflow task type
43
+ ```
44
+
45
+ ## Quickstart
46
+
47
+ _Coming with stage 2 — once the worker core lands, this section documents
48
+ `kartikeya worker` end to end (submit → worker runs → poll)._
49
+
50
+ ## License
51
+
52
+ MIT © Sean Campbell
@@ -0,0 +1,197 @@
1
+ # Spec: Kart Lift — extract a standalone `kart` package
2
+
3
+ Status: DRAFT for review (2026-07-08). Engineering spec for the migration whose
4
+ direction is set in `kart-productionization.md`. Resolves B-22.
5
+
6
+ **Decisions locked (operator, 2026-07-08):**
7
+ 1. **Shared package** — Kart becomes its own installable package; willow-mcp
8
+ (and later willow-2.0) *depend* on it rather than vendoring a copy. No drift.
9
+ 2. **Product-neutral default** sandbox mount policy.
10
+ 3. **SQLite task backend** — the queue must run with **no Postgres**; a
11
+ zero-infra `pip install` can execute tasks.
12
+
13
+ The big consequence: **the `kart` package must not import willow-mcp or
14
+ willow-2.0.** Its coupling to a host (DB access, `$WILLOW_HOME`) is inverted
15
+ into a small **backend interface** the host implements. Kart owns the sandbox,
16
+ worker loop, lanes, and scan; the host owns "where tasks live" and "where files
17
+ live."
18
+
19
+ ## 0. Goal & acceptance
20
+
21
+ A clean `pip install willow-mcp` (which pulls in `kart`) can execute a submitted
22
+ task end-to-end with **no Postgres and no willow-2.0 present**:
23
+ ```
24
+ pip install willow-mcp # depends on kart
25
+ willow-mcp worker & # drains the queue via the SQLite backend
26
+ # via MCP: task_submit(task="echo hi") -> task_status -> {status: completed, result: "hi"}
27
+ ```
28
+ plus the same for an `allow_net=True` task with `task_net` granted (sandbox +
29
+ gate work standalone), and the `kart` suite green with neither willow-mcp nor
30
+ willow-2.0 on `sys.path`.
31
+
32
+ ## 1. The `kartikeya` package
33
+
34
+ New **standalone repo** (operator decision). Distribution + import name
35
+ **`kartikeya`** — bringing back Kart's full name (Skanda / Murugan, the
36
+ six-faced commander of the divine armies; `docs/audits/KART_SANDBOX_AUDIT_2026-06-11.md`).
37
+ "Kart" stays the colloquial short form in prose and existing `kart:*` task ids.
38
+ ~2,200 LOC lifted from willow-2.0 `core/kart_*`; own `pyproject`; depends only
39
+ on stdlib + optional extras.
40
+
41
+ ```
42
+ kartikeya/ # new standalone GitHub repo
43
+ pyproject.toml # name = "kartikeya"; deps: none (base); extras: [llm]
44
+ src/kartikeya/
45
+ __init__.py # run_worker(), execute_task_row(), TaskQueue
46
+ sandbox.py # from kart_sandbox.py
47
+ execute.py # from kart_execute.py
48
+ worker.py # from kart_worker.py — takes a TaskQueue
49
+ lanes.py # from kart_lanes.py
50
+ task_scan.py # from kart_task_scan.py
51
+ queue.py # TaskQueue ABC + SqliteTaskQueue reference impl
52
+ config.py # sandbox mount-policy loader + neutral default
53
+ data/kart-sandbox.json # product-neutral default (§5); filename kept for continuity
54
+ tests/ # carried test_kart_* + queue-backend tests
55
+ ```
56
+ Console script: `kartikeya worker` (with a `kart` alias for muscle memory).
57
+ willow-mcp keeps its own `willow-mcp worker` subcommand that constructs the
58
+ backend and calls into the library (§3).
59
+
60
+ ### 1a. Dependency dispositions
61
+
62
+ | willow-2.0 dependency | Disposition in `kart` |
63
+ |---|---|
64
+ | `kart_sandbox/execute/worker/lanes/task_scan` | **Lifted in** as the package core |
65
+ | `core.pg_bridge.PgBridge` | **Inverted** → `TaskQueue` interface (§2); host supplies impl |
66
+ | `willow.fylgja.willow_home` | **Inverted** → host passes a work-root; `kart` falls back to `$WILLOW_HOME`/CWD |
67
+ | `willow.fylgja.python_env` | **Reimplemented** minimally in `kart` (stdlib `sysconfig` + venv detect) |
68
+ | `core.loop_heartbeat` | **Callback seam** — `on_heartbeat` hook, default no-op |
69
+ | `core.run_ledger` | **Callback seam** — `on_run_event` hook, default no-op |
70
+ | `core.grove_gate` | **Dropped** (fleet governance) |
71
+ | `core.outcomes` | **Dropped** (default) / host callback if wanted |
72
+ | `core.llm_edge` | **Optional extra** `kart[llm]`; LLM task type disabled if absent |
73
+
74
+ No `core.*` / `willow.fylgja.*` import survives in `kart`.
75
+
76
+ ## 2. The `TaskQueue` backend interface
77
+
78
+ The one seam that inverts host coupling. `kart` defines the ABC; the worker
79
+ loop is written against it:
80
+
81
+ ```python
82
+ class TaskQueue(ABC):
83
+ @abstractmethod
84
+ def claim_pending(self, agent: str, limit: int) -> list[TaskRow]: ... # atomic claim → 'running'
85
+ @abstractmethod
86
+ def mark_running(self, task_id: str) -> None: ...
87
+ @abstractmethod
88
+ def mark_done(self, task_id: str, *, status: str, result: str) -> None: ... # completed|failed + completed_at
89
+ @abstractmethod
90
+ def pending_count(self) -> QueueStats: ... # for liveness/fleet_health
91
+ ```
92
+ `TaskRow` = `{task_id, task, agent, submitted_by, status}`.
93
+
94
+ Three implementations:
95
+ - **`SqliteTaskQueue`** (shipped *in* `kart`) — reference/zero-infra backend.
96
+ Atomic claim via a single `UPDATE tasks SET status='running' WHERE task_id IN
97
+ (SELECT task_id FROM tasks WHERE status='pending' AND agent=? LIMIT ?)
98
+ RETURNING …` inside `BEGIN IMMEDIATE` (SQLite serializes writers; safe).
99
+ - **willow-mcp's Postgres impl** (in willow-mcp) — maps through willow-mcp's
100
+ schema-adaptation (`_TASK_FIELDS`), so it works against an *adopted* `tasks`
101
+ table, using `FOR UPDATE SKIP LOCKED` for the claim.
102
+ - **willow-2.0's impl** (later) — wraps its existing `PgBridge`.
103
+
104
+ This is also exactly what makes the **SQLite backend** (decision 3) fall out
105
+ naturally rather than being bolted on.
106
+
107
+ ## 3. willow-mcp integration
108
+
109
+ willow-mcp stays thin — it does **not** contain sandbox/worker code:
110
+ - Adds `kart` to `dependencies`.
111
+ - Implements `WillowMcpTaskQueue(TaskQueue)` over its adopted `tasks` table
112
+ (Postgres via schema-adaptation) **and** wires the shipped `SqliteTaskQueue`
113
+ for the no-Postgres path; backend chosen by config (Postgres if `WILLOW_PG_*`
114
+ present, else SQLite under `WILLOW_STORE_ROOT`).
115
+ - Adds `willow-mcp worker` (argparse subcommand, consistent with `--serve`):
116
+ `--lane fast|batch`, `--slots N`, `--once`. Constructs the backend + calls
117
+ `kart.run_worker(queue=…, lane=…)`.
118
+ - Ships the `CREATE TABLE tasks` DDL the review flagged missing
119
+ (`docs/schema/`), for both SQLite and Postgres, matching `_TASK_FIELDS`.
120
+
121
+ ## 4. Security posture (preserve + test)
122
+
123
+ - **bwrap isolation** and **credential-prefix gating** carry over unchanged.
124
+ - **Net-directive contract stays split (B-21 ↔ B-22):** the worker grants
125
+ egress iff the *stored task text* has a `# allow_net` line; willow-mcp's
126
+ `task_submit` is the only writer of that line, only under `task_net`,
127
+ stripping caller copies. Ship an **end-to-end test in willow-mcp**: a
128
+ `task_queue`-only app submitting `task="curl …\n# allow_net"` with
129
+ `allow_net=False` runs **network-isolated**; a `task_net` app with
130
+ `allow_net=True` runs with egress. Most likely seam to regress in the lift.
131
+ - `kart` also gets a unit test that `task_allows_network()` still keys on
132
+ `line.strip() == "# allow_net"` exactly (the contract willow-mcp's strip
133
+ depends on).
134
+
135
+ ## 5. Sandbox config — product-neutral default
136
+
137
+ Vendored `kart/data/kart-sandbox.json`: keep `WILLOW_`, `PG`, `POSTGRES`,
138
+ `OLLAMA_`, `GIT_` prefixes and generic bind paths; **drop** fleet-only
139
+ `GROVE_`/`SAFE_` prefixes and fleet bind paths from the *default*. Resolution:
140
+ `$KART_SANDBOX_CONFIG` → `$WILLOW_HOME/kart-sandbox.json` → vendored default.
141
+ Templating (`{{HOME}}`, `{{WILLOW_ROOT}}`) preserved. The fleet keeps its richer
142
+ policy via the override file — parity without shipping fleet surface.
143
+
144
+ ## 6. Test migration
145
+
146
+ Carry `tests/test_kart_*.py` into `kart/tests/`, replacing fleet imports with a
147
+ fake `TaskQueue`, a tmp `kart-sandbox.json`, and no-op heartbeat/run callbacks.
148
+ Add `SqliteTaskQueue` backend tests (concurrent claim, no double-execution).
149
+ Gate bwrap tests on `bwrap_available()` so CI without bwrap skips, not fails.
150
+
151
+ ## 7. Optional LLM task type
152
+
153
+ `kart[llm]` extra. Base worker runs shell tasks with zero LLM deps; an LLM task
154
+ submitted without the extra fails cleanly (`{"error": "llm task type requires
155
+ kart[llm]"}`), never an import crash. (willow-2.0 supplies its own `llm_edge`
156
+ adapter behind the extra's hook.)
157
+
158
+ ## 8. Staged PRs / milestones
159
+
160
+ Spans two (maybe three) repos; sequence willow-mcp value first.
161
+
162
+ 1. **Extract `kart` (new package):** lift the 5 files, sever fleet imports per
163
+ §1, define `TaskQueue` + `SqliteTaskQueue`, callback seams, neutral config.
164
+ *Acceptance: `kart`'s own suite green standalone; `pip install kart` +
165
+ SqliteTaskQueue executes a shell task in a sandbox.*
166
+ 2. **willow-mcp integration:** depend on `kart`, add `WillowMcpTaskQueue`
167
+ (Pg + SQLite), `willow-mcp worker`, DDL. *Acceptance: §0 end-to-end on a
168
+ clean venv, no Postgres.*
169
+ 3. **Security e2e + docs → B-22 Fixed:** the §4 net-gate e2e test, README
170
+ quickstart, fill `skills/kart-tasks.md` §0 worker-run section, honest
171
+ `pyproject`.
172
+ 4. **Liveness:** worker heartbeat via the `on_heartbeat` seam surfaced in
173
+ `fleet_health`/`diagnostic_summary` (review §1).
174
+ 5. **willow-2.0 migration (separate, later):** point willow-2.0 at the `kart`
175
+ package, delete its `core/kart_*`. Ends drift. Can trail well behind stage 3.
176
+ 6. **Optional:** `kart[llm]`, systemd templates, batch-lane polish.
177
+
178
+ ## 9. Decisions & remaining questions
179
+
180
+ **Locked:**
181
+ - Repo: **new standalone GitHub repo** (operator).
182
+ - Name: **`kartikeya`** (operator — "bring back Kart's full name").
183
+ - Shared package · product-neutral default · SQLite backend (top of doc).
184
+
185
+ **Working assumptions (operator may override):**
186
+ - **willow-2.0 migration is deferred to stage 5** — accepting a temporary
187
+ window where willow-2.0 keeps its `core/kart_*` copy while willow-mcp depends
188
+ on `kartikeya`. Rationale: ship willow-mcp value (close B-22) before touching
189
+ the live fleet.
190
+ - **`kartikeya` publish stays under the operator gate**, same as willow-mcp
191
+ (release-state hold), until explicitly released — even though its surface is
192
+ lower-risk than willow-mcp's OAuth layer.
193
+
194
+ **Still open:**
195
+ - Confirm PyPI `kartikeya` is claimable (almost certainly; verify at extract
196
+ time) and that the `kart` alias console-script name doesn't collide.
197
+ ```
@@ -0,0 +1,47 @@
1
+ [build-system]
2
+ requires = ["hatchling"]
3
+ build-backend = "hatchling.build"
4
+
5
+ [project]
6
+ name = "kartikeya"
7
+ version = "0.0.1"
8
+ description = "Kartikeya — a standalone bubblewrap-sandboxed task queue and worker. Backend-agnostic (SQLite or Postgres); the execution engine formerly known as Kart."
9
+ readme = "README.md"
10
+ license = { text = "MIT" }
11
+ authors = [{ name = "Sean Campbell" }]
12
+ requires-python = ">=3.11"
13
+ keywords = ["task-queue", "sandbox", "bubblewrap", "bwrap", "worker", "kart", "willow"]
14
+ classifiers = [
15
+ "Development Status :: 3 - Alpha",
16
+ "Intended Audience :: Developers",
17
+ "License :: OSI Approved :: MIT License",
18
+ "Operating System :: POSIX :: Linux",
19
+ "Programming Language :: Python :: 3",
20
+ "Programming Language :: Python :: 3.11",
21
+ "Programming Language :: Python :: 3.12",
22
+ "Programming Language :: Python :: 3.13",
23
+ "Topic :: System :: Distributed Computing",
24
+ "Topic :: Software Development :: Libraries",
25
+ ]
26
+ dependencies = []
27
+
28
+ [project.optional-dependencies]
29
+ # LLM-backed "workflow" task type. Base worker runs shell tasks with zero LLM deps.
30
+ llm = []
31
+ # Reference Postgres backend helpers (SQLite backend needs no extra).
32
+ postgres = ["psycopg2-binary>=2.9,<3.0"]
33
+
34
+ [project.scripts]
35
+ kartikeya = "kartikeya.worker:main"
36
+ kart = "kartikeya.worker:main"
37
+
38
+ [project.urls]
39
+ Homepage = "https://github.com/rudi193-cmd/kartikeya"
40
+ Repository = "https://github.com/rudi193-cmd/kartikeya"
41
+ Issues = "https://github.com/rudi193-cmd/kartikeya/issues"
42
+
43
+ [tool.hatch.build.targets.wheel]
44
+ packages = ["src/kartikeya"]
45
+
46
+ [tool.pytest.ini_options]
47
+ testpaths = ["tests"]
@@ -0,0 +1,32 @@
1
+ """Kartikeya — standalone sandboxed task queue + worker (a.k.a. Kart).
2
+
3
+ Public surface:
4
+ - Task-queue backend seam: `TaskQueue`, `TaskRow`, `QueueStats`, `SqliteTaskQueue`.
5
+ - Execution lanes: `lanes` (fast/batch constants + worker-mode helpers).
6
+ - Task security gate: `check_kart_task` (hybrid scan over task text).
7
+ - Execution: `execute_task_row`, `drain_claimed_tasks`, `run_shell_task`.
8
+ - Worker loop: `run_worker`.
9
+ """
10
+ from __future__ import annotations
11
+
12
+ from . import lanes
13
+ from .execute import drain_claimed_tasks, execute_task_row, run_shell_task
14
+ from .queue import QueueStats, SqliteTaskQueue, TaskQueue, TaskRow
15
+ from .task_scan import check_kart_task
16
+ from .worker import run_worker
17
+
18
+ __version__ = "0.0.1"
19
+
20
+ __all__ = [
21
+ "TaskQueue",
22
+ "TaskRow",
23
+ "QueueStats",
24
+ "SqliteTaskQueue",
25
+ "lanes",
26
+ "check_kart_task",
27
+ "run_shell_task",
28
+ "execute_task_row",
29
+ "drain_claimed_tasks",
30
+ "run_worker",
31
+ "__version__",
32
+ ]
@@ -0,0 +1,87 @@
1
+ {
2
+ "version": 1,
3
+ "description": "Kartikeya bwrap mount policy (product-neutral default). Override via $KART_SANDBOX_CONFIG or $WILLOW_HOME/kart-sandbox.json to add host/fleet-specific paths without editing code.",
4
+ "env_prefixes": [
5
+ "WILLOW_",
6
+ "PG",
7
+ "POSTGRES",
8
+ "OLLAMA_",
9
+ "GIT_",
10
+ "TWINE_",
11
+ "PYPI_",
12
+ "ANTHROPIC_",
13
+ "OPENROUTER_",
14
+ "GROQ_",
15
+ "GITHUB_",
16
+ "NPM_",
17
+ "NODE_",
18
+ "SSH_AUTH",
19
+ "HUGGINGFACE_",
20
+ "HF_",
21
+ "OPENAI_",
22
+ "AWS_",
23
+ "DBUS_",
24
+ "XDG_"
25
+ ],
26
+ "credential_env_prefixes": [
27
+ "TWINE_",
28
+ "PYPI_",
29
+ "ANTHROPIC_",
30
+ "OPENROUTER_",
31
+ "GROQ_",
32
+ "GITHUB_",
33
+ "NPM_",
34
+ "HUGGINGFACE_",
35
+ "HF_",
36
+ "OPENAI_",
37
+ "AWS_"
38
+ ],
39
+ "bind_read_only": [
40
+ "/usr",
41
+ "/etc",
42
+ "/sys",
43
+ "{{HOME}}/github",
44
+ "{{HOME}}/.config/git",
45
+ "{{HOME}}/.config/systemd"
46
+ ],
47
+ "bind_read_write": [
48
+ "{{WILLOW_ROOT}}",
49
+ "{{HOME}}/.willow",
50
+ "{{HOME}}/.local",
51
+ "/var/run/postgresql"
52
+ ],
53
+ "bind_try": [
54
+ "{{WILLOW_ROOT}}/.venv-dev",
55
+ "{{HOME}}/.willow-venv",
56
+ "{{HOME}}/.gitconfig",
57
+ "{{HOME}}/.npmrc",
58
+ "{{HOME}}/.cargo",
59
+ "{{HOME}}/.npm",
60
+ "{{HOME}}/.cache/uv",
61
+ "{{HOME}}/.cache/pip",
62
+ "{{HOME}}/.cache/pre-commit",
63
+ "{{HOME}}/.config/pip",
64
+ "{{HOME}}/.config/pypoetry",
65
+ "{{HOME}}/.local/share/uv",
66
+ "/run/user",
67
+ "/run/media",
68
+ "{{XDG_RUNTIME_DIR}}",
69
+ "/run/systemd/resolve"
70
+ ],
71
+ "bind_try_read_only": [
72
+ "/lib32"
73
+ ],
74
+ "worktree_scan_roots": [
75
+ "{{WILLOW_ROOT}}/worktrees"
76
+ ],
77
+ "rtk_compress": {
78
+ "enabled": false
79
+ },
80
+ "_security_notes": {
81
+ "github_ro": "~/github is read-only by default; WILLOW_ROOT + its worktrees nest read-write on top. Hosts promote additional repos to RW via an override config.",
82
+ "ssh_dropped": "~/.ssh is not bound. SSH git uses SSH_AUTH_SOCK (via /run/user) + known_hosts (ro), both only on allow_net. Private keys never enter the sandbox.",
83
+ "creds_gated": "credential_env_prefixes (and ~/.config/gh, ~/.netrc) are present only on allow_net. A no-network task gets zero credentials.",
84
+ "localhost_tier": "# allow_localhost shares the host network namespace (loopback works) but still strips credentials. Weaker than --unshare-net; prefer over allow_net for local-only work.",
85
+ "tmp_tmpfs": "/tmp + /dev/shm are private tmpfs, not host binds."
86
+ }
87
+ }