Skip to content

Commit 31cfb59

Browse files
gracexmatinclaude
andcommitted
Merge origin/main into add_RSS_Feed
main's #170 rewrote the CLI as a thin HTTP client with no local engine, so this branch's CLI-side rss wiring (the `rss:` block on LocalDataSource, the `rss` arm of register_source, and the crate's `rss` feature) has nothing left to attach to and is dropped with it — rss sources are configured on the server, whose wiring merged cleanly. Union resolutions for the skardi crate's Cargo.toml (our rss feature + main's object_store) and the README source table (main's updated Open Connector / Documents rows + our RSS row). docs/rss.md's build-flag example updated to the thin-client invocation. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2 parents e90de55 + 84323ab commit 31cfb59

91 files changed

Lines changed: 11355 additions & 6776 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/ci.yml

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -554,9 +554,80 @@ jobs:
554554
# NULL-bearing row: no `category` attribute, exercising NULL handling.
555555
put '{"product_id":{"S":"PROD005"},"name":{"S":"Desk Chair"},"price":{"N":"199.99"},"in_stock":{"BOOL":true}}'
556556
557+
- name: Start skardi-server for CLI e2e smoke tests
558+
run: |
559+
# The CLI's #[ignore] e2e_smoke tests are integration tests whose
560+
# backing service is skardi-server itself; they hit the default
561+
# http://127.0.0.1:8080 (no ctx/pipelines needed). The nextest step
562+
# above already compiled the server binary into the llvm-cov
563+
# target dir, so this starts without rebuilding.
564+
./target/llvm-cov-target/debug/skardi-server --port 8080 &
565+
for i in $(seq 1 30); do
566+
curl -sf http://127.0.0.1:8080/health >/dev/null && exit 0
567+
sleep 1
568+
done
569+
echo "skardi-server failed to become healthy" >&2
570+
exit 1
571+
557572
- name: Execute Integration tests
558573
run: cargo llvm-cov --no-report nextest --all-features -- --ignored
559574

575+
# MinIO gives the `documents` connector's object-store path real S3
576+
# coverage without needing an AWS account or credentials in CI. Started
577+
# with `docker run` rather than a `services:` entry because service
578+
# containers cannot override the image command, and the MinIO image needs
579+
# `server /data`.
580+
- name: Start MinIO for documents S3 tests
581+
run: |
582+
docker run -d --name skardi-minio \
583+
-p 127.0.0.1:9000:9000 \
584+
-e MINIO_ROOT_USER=skardiminio \
585+
-e MINIO_ROOT_PASSWORD=skardiminio123 \
586+
quay.io/minio/minio server /data
587+
# The image has no shell tooling for a container healthcheck, so poll
588+
# readiness from the runner (same approach as DynamoDB Local above).
589+
for i in $(seq 1 30); do
590+
if curl -fsS http://127.0.0.1:9000/minio/health/live >/dev/null 2>&1; then
591+
echo "minio ready after ${i}s"
592+
break
593+
fi
594+
if [ "$i" = "30" ]; then
595+
echo "minio failed to become ready"
596+
docker logs skardi-minio
597+
exit 1
598+
fi
599+
sleep 1
600+
done
601+
AWS_ACCESS_KEY_ID=skardiminio AWS_SECRET_ACCESS_KEY=skardiminio123 \
602+
aws --endpoint-url http://127.0.0.1:9000 s3 mb s3://skardi-ci-documents
603+
604+
# These are `#[ignore]`d and skip themselves unless DOCUMENTS_S3_LIVE=1, so
605+
# the step above's credentials are what actually arms them. Set at step
606+
# scope, not job scope: the job-level AWS_* values are the `dummy`
607+
# placeholders DynamoDB Local expects, and MinIO rejects a root password
608+
# shorter than 8 characters.
609+
- name: Execute documents S3 live tests against MinIO
610+
env:
611+
DOCUMENTS_S3_LIVE: "1"
612+
DOCUMENTS_S3_BUCKET: skardi-ci-documents
613+
# `AmazonS3Builder::from_env()` honours both of these, so the real S3
614+
# HTTP client path is exercised, not a stub.
615+
AWS_ENDPOINT: http://127.0.0.1:9000
616+
AWS_ALLOW_HTTP: "true"
617+
AWS_REGION: us-east-1
618+
AWS_ACCESS_KEY_ID: skardiminio
619+
AWS_SECRET_ACCESS_KEY: skardiminio123
620+
# `--no-tests=fail` is explicit rather than relying on the current
621+
# default: if these tests are ever renamed out of the filter's reach, the
622+
# step must fail loudly instead of reporting success having run nothing.
623+
run: |
624+
cargo llvm-cov --no-report nextest --all-features \
625+
-E 'test(/live_s3_/)' --no-tests=fail -- --ignored
626+
627+
- name: Stop MinIO
628+
if: always()
629+
run: docker rm -f skardi-minio || true
630+
560631
- name: Generate coverage report (lcov)
561632
run: cargo llvm-cov report --lcov --output-path lcov.info
562633

Cargo.lock

Lines changed: 57 additions & 11 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

README.md

Lines changed: 40 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@
4343
**The most agent-friendly backend for builders shipping their first AI agent.** The painful part of agent-building isn't the prompt — it's the data plumbing: a vector DB to stand up, an embedding pipeline to maintain, a chunker to debug, a tool-call wrapper to write for every query. Skardi auto-bootstraps the primitives every agent needs so you ship in hours, not weeks:
4444

4545
- **[`auto_rag`](https://github.com/SkardiLabs/skardi-skills/tree/main/auto_rag) — Auto-RAG (Retrieval Augmented Generation).** Server-backed hybrid search (vector + full-text + RRF) via `skardi-server` over a datastore you already control (Postgres + pgvector, MongoDB, or Lance). The skill renders the config, starts the server, and drives ingestion and queries through REST. One command from a datastore to a working retrieval API your agent calls as a tool — no Python orchestration layer, no glue code.
46-
- **[`auto_knowledge_base`](https://github.com/SkardiLabs/skardi-skills/tree/main/auto_knowledge_base) — Auto agent knowledge base.** Point it at a directory of documents and you have a queryable, citable local KB one command later. Chunking, embedding, indexing, and hybrid search are exposed to your agent as a `skardi grep` verb. Zero infra by default (SQLite + local embeddings), so any Claude Code / Cursor session gets a grounded knowledge base over your files.
46+
- **[`auto_knowledge_base`](https://github.com/SkardiLabs/skardi-skills/tree/main/auto_knowledge_base) — Auto agent knowledge base.** Point it at a directory of documents and you have a queryable, citable local KB one command later. Chunking, embedding, indexing, and hybrid search are exposed to your agent as a `skardi run` verb. Zero infra by default (SQLite + local embeddings), so any Claude Code / Cursor session gets a grounded knowledge base over your files.
4747
- **Zero bootstrap**`ctx.yaml`, pipelines, schema, server, all rendered for you by **[skardi-skills](https://github.com/SkardiLabs/skardi-skills)**. Install once and your agent has a working data tool the same hour.
4848

4949
You build the agent. Skardi handles the data plane.
@@ -96,8 +96,8 @@ spec:
9696
```
9797
9898
```bash
99-
$ skardi grep "turing machines" --limit=10 # shell tool, any Bash-tool agent
100-
$ curl -X POST :8080/wiki-search-hybrid/execute -d '{...}' # same pipeline, served as REST
99+
$ skardi run wiki-search-hybrid -p query="turing machines" -p limit=10 # shell tool, any Bash-tool agent
100+
$ curl -X POST :8080/wiki-search-hybrid/execute -d '{...}' # same pipeline, served as REST
101101
```
102102

103103
That uniformity is also what makes the *durable* reason to put a plane in front possible: **governance**. Once every read and write goes through one engine, three primitives compose on top of it instead of fragmenting across N SDKs:
@@ -120,7 +120,7 @@ For the longer technical read — each primitive's shipped vs. in-progress statu
120120
(YAML pipelines)
121121
```
122122

123-
- **`skardi` CLI**run federated SQL or any pipeline directly from a shell. Drop it into Claude Code, Cursor, or any agent with a Bash tool and it's wired with no MCP config.
123+
- **`skardi` CLI**a thin HTTP client: send ad-hoc SQL or call any pipeline against a running `skardi-server`, right from a shell. Drop it into Claude Code, Cursor, or any agent with a Bash tool and it's wired with no MCP config.
124124
- **`skardi-server`** — same engine over HTTP, with two surfaces: **online serving** (a YAML pipeline becomes a parameterized REST endpoint with an inferred request/response schema) and **offline jobs** (async batch writes into Lance or any read-write DB; if a job fails halfway you don't get a corrupted dataset, and every run is logged in a SQLite ledger you can list and inspect).
125125
- **Skardi-server is stateful but lightweight** — a single Rust process, plus a small SQLite file for the run ledger and (optional) auth. One server can serve many agents; deploy it next to your data, behind your usual auth.
126126

@@ -181,14 +181,11 @@ sudo mv skardi /usr/local/bin/
181181
182182
### First-time agent loop (two minutes)
183183

184-
**Step 1 — ad-hoc SQL, no server, no pre-registration.** The CLI prints results as a pretty-printed table to stdout — see [docs/cli.md](docs/cli.md).
184+
The CLI is a thin HTTP client — every command below talks to a running
185+
`skardi-server`, so step 1 is always starting one. See
186+
[docs/cli.md](docs/cli.md) for the full command reference.
185187

186-
```bash
187-
skardi query --sql "SELECT * FROM './data/products.csv' LIMIT 10"
188-
skardi query --sql "SELECT * FROM 's3://mybucket/events.parquet' LIMIT 10"
189-
```
190-
191-
**Step 2 — register named sources in a `ctx.yaml`.** Five example lines:
188+
**Step 1 — register named sources in a `ctx.yaml`, and start the server.** Five example lines:
192189

193190
```yaml
194191
# ctx.yaml — describes where your data lives. Each entry gets a name you use in SQL.
@@ -209,12 +206,23 @@ spec:
209206
```
210207

211208
```bash
212-
skardi query --ctx ./ctx.yaml --sql "SELECT * FROM products LIMIT 10"
209+
cargo run --bin skardi-server -- --ctx ./ctx.yaml --port 8080
213210
```
214211

215-
**Step 3 — turn a parameterized SQL into an agent-callable verb.** Two YAMLs from [`demo/llm_wiki/cli/`](demo/llm_wiki/cli/) — the actual files, not pseudo-code:
212+
**Step 2 — ad-hoc SQL against the running server.** The CLI prints the
213+
response's `data` array as pretty-printed JSON to stdout by default (pass
214+
`--table` for an ASCII table) — see [docs/cli.md](docs/cli.md).
215+
216+
```bash
217+
skardi query -e "SELECT * FROM products LIMIT 10"
218+
skardi query -e "SELECT * FROM products LIMIT 10" --table
219+
```
216220

217-
> ⚠️ Unlike Steps 1–2 (zero-dependency), this hybrid-search verb also needs a local embedding model at `models/…` + the `sqlite-vec` extension (`SQLITE_VEC_PATH`) and a seeded DB — so it is **not runnable by copy-paste alone**. The [`auto_knowledge_base` skill](https://github.com/SkardiLabs/skardi-skills/tree/main/auto_knowledge_base) sets all of this up for you; use it if you just want the verb working.
221+
**Step 3 — turn a parameterized SQL into an agent-callable pipeline.** One
222+
YAML from [`demo/llm_wiki/cli/`](demo/llm_wiki/cli/) — the actual file, not
223+
pseudo-code:
224+
225+
> ⚠️ Unlike Steps 1–2 (zero-dependency), this hybrid-search pipeline also needs a local embedding model at `models/…` + the `sqlite-vec` extension (`SQLITE_VEC_PATH`) and a seeded DB — so it is **not runnable by copy-paste alone**. The [`auto_knowledge_base` skill](https://github.com/SkardiLabs/skardi-skills/tree/main/auto_knowledge_base) sets all of this up for you; use it if you just want the pipeline working.
218226
219227
```yaml
220228
# pipelines/search_hybrid.yaml — declares the SQL once; Skardi infers the params
@@ -239,24 +247,22 @@ spec:
239247
ORDER BY rrf_score DESC LIMIT {limit}
240248
```
241249
242-
```yaml
243-
# aliases.yaml — gives the pipeline a short shell verb, with positional + default args
244-
kind: aliases
245-
spec:
246-
grep:
247-
pipeline: wiki-search-hybrid
248-
positional: [query]
249-
defaults: { text_query: "{query}", text_weight: "0.5", vector_weight: "0.5", limit: "10" }
250-
description: Hybrid search over the wiki (RRF of sqlite_knn + sqlite_fts)
251-
```
252-
253-
Now any agent with a shell can call it:
250+
Restart the server with `--pipeline pipelines/` so it loads this file (see
251+
[Skardi Server](#skardi-server--online-serving--offline-jobs) below), and
252+
any agent with a shell can call it by name — no separate alias file, no
253+
alias-management step:
254254

255255
```bash
256-
skardi grep "turing machine computation" --limit=10
256+
skardi run wiki-search-hybrid \
257+
-p query="turing machine computation" \
258+
-p text_query="turing machine computation" \
259+
-p vector_weight=0.5 -p text_weight=0.5 -p limit=10
257260
```
258261

259-
The output your agent sees is the standard Arrow-pretty table on stdout (`+----+--------+ ...`). Over the server (next section), the same pipeline is mounted at `POST /wiki-search-hybrid/execute` — the request body is a JSON object whose keys match the `{...}` placeholders in the SQL (Skardi infers this schema and serves it on `GET /data_source` so the agent can read it). One full cycle:
262+
The same pipeline is mounted at `POST /wiki-search-hybrid/execute` — the
263+
request body is a JSON object whose keys match the `{...}` placeholders in
264+
the SQL (Skardi infers this schema and serves it on `GET /data_source` so
265+
the agent can read it). One full cycle:
260266

261267
```bash
262268
curl -X POST http://localhost:8080/wiki-search-hybrid/execute \
@@ -272,7 +278,7 @@ curl -X POST http://localhost:8080/wiki-search-hybrid/execute \
272278
"rows": 10, "execution_time_ms": 23 }
273279
```
274280

275-
Drop `skardi` into a Claude Code or Cursor session and the agent can already use any pipeline you've declared as a tool via its Bash integration. No MCP config, no separate server — that's the MVP design intent.
281+
Drop `skardi` into a Claude Code or Cursor session and the agent can already use any pipeline you've declared as a tool via its Bash integration, as long as a `skardi-server` is reachable — no MCP config needed.
276282

277283
### Skardi Server — online serving + offline jobs
278284

@@ -330,8 +336,8 @@ For end-to-end walkthroughs — RAG, recommendations, an agent-native wiki, a si
330336
| S3 / GCS / Azure | Read | No | CSV, Parquet, Lance from object stores | [docs/S3_USAGE.md](docs/S3_USAGE.md) |
331337
| Apache Iceberg | Read | No | Schema evolution, partition pruning | [docs/iceberg/](docs/iceberg/) |
332338
| InfluxDB 3 | Read | No | Time-series measurements over Arrow Flight SQL | [docs/influxdb/](docs/influxdb/) |
333-
| Open Connector | Read | Yes | SaaS resources as stable SQL tables via a self-hosted [Open Connector](https://github.com/oomol-lab/open-connector) gateway; GitHub pack (repos, issues, PRs, reviews, commits, workflow runs, releases — [guide](docs/open-connector-github.md)), `open_connector_query` / `open_connector_scan` UDTFs, filter + limit pushdown, bounded TTL cache (more provider packs rolling out) | [docs/open-connector.md](docs/open-connector.md), [demo](docs/open-connector/) |
334-
| Documents | Read | No | PDF/Office/ODF/image -> per-page markdown, tables, images (local directories; `documents` feature) | [docs/documents.md](docs/documents.md) |
339+
| Open Connector | Read | Yes | SaaS resources as stable SQL tables via a self-hosted [Open Connector](https://github.com/oomol-lab/open-connector) gateway; GitHub pack (repos, issues, PRs, reviews, commits, workflow runs, releases — [guide](docs/open-connector-github.md)), Slack pack (conversations, users, files — [guide](docs/open-connector-slack.md)), `open_connector_query` / `open_connector_scan` UDTFs, filter + limit pushdown, bounded TTL cache (more provider packs rolling out) | [docs/open-connector.md](docs/open-connector.md), [demo](docs/open-connector/) |
340+
| Documents | Read | No | PDF/Office/ODF/image -> per-page markdown, tables, images (local directories or S3 prefixes; `documents` feature) | [docs/documents.md](docs/documents.md) |
335341
| RSS / Atom | Read | Yes | RSS 0.9x/1.0/2.0, Atom, JSON Feed subscriptions as `feeds` (health) + `items` (live window); content stored as Markdown, per-feed TTL cache with conditional GETs, per-feed fault isolation, default-deny SSRF egress guard (`rss` feature) | [docs/rss.md](docs/rss.md) |
336342

337343
---
@@ -442,8 +448,8 @@ We're **building in public**. `[x]` means shipped today, `[ ]` means open for co
442448
`3` Online serving (pipelines)
443449
- [x] Declarative YAML → parameterized REST endpoint with inferred request / response schema
444450
- [x] Built-in pipeline dashboard
445-
- [x] CLI pipeline binding + aliases `skardi run <pipeline> --param=…` and user-defined verb aliases ([#90](https://github.com/SkardiLabs/skardi/pull/90))
446-
- [x] CLI federated SQL `skardi query` against files, object stores, datalake formats, and databases with no server required
451+
- [x] CLI pipeline binding — `skardi run <pipeline> -p name=value` calls any named, server-loaded pipeline directly ([#90](https://github.com/SkardiLabs/skardi/pull/90))
452+
- [x] CLI as a thin HTTP client — `skardi query` / `skardi run` send ad-hoc SQL and pipeline calls to a running `skardi-server` over the network; federation across sources happens server-side (see [docs/cli.md](docs/cli.md))
447453

448454
`4` Offline jobs
449455
- [x] Async batch execution with submit / poll / cancel ([#98](https://github.com/SkardiLabs/skardi/pull/98))
@@ -454,7 +460,7 @@ We're **building in public**. `[x]` means shipped today, `[ ]` means open for co
454460
`5` Agent-facing bindings
455461
- [x] REST — every pipeline served as a parameterized HTTP endpoint
456462
- [x] Shell — every pipeline runnable as a `skardi` command; works in Claude Code, Cursor, and any agent with a Bash tool
457-
- [ ] Skills generator — `skardi skills generate --ctx <ctx.yaml> --out .claude/skills/` emits a skill Markdown per pipeline for Claude Code / Desktop auto-discovery
463+
- [ ] Skills generator — `skardi skills generate --server <URL> --out .claude/skills/` emits a skill Markdown per pipeline for Claude Code / Desktop auto-discovery
458464
- [ ] MCP binding — same pipeline YAML projected to MCP tools for non-Claude hosts
459465

460466
`6` Governance & lineage

0 commit comments

Comments
 (0)