foliq 0.1.0a1__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.
- foliq-0.1.0a1/.github/workflows/ci.yml +46 -0
- foliq-0.1.0a1/.github/workflows/docs.yml +37 -0
- foliq-0.1.0a1/.github/workflows/release.yml +142 -0
- foliq-0.1.0a1/.gitignore +11 -0
- foliq-0.1.0a1/.python-version +1 -0
- foliq-0.1.0a1/AGENTS.md +95 -0
- foliq-0.1.0a1/CLAUDE.md +95 -0
- foliq-0.1.0a1/Cargo.lock +2738 -0
- foliq-0.1.0a1/Cargo.toml +33 -0
- foliq-0.1.0a1/LICENSE +21 -0
- foliq-0.1.0a1/PKG-INFO +248 -0
- foliq-0.1.0a1/README.md +229 -0
- foliq-0.1.0a1/benchmarks/.gitignore +2 -0
- foliq-0.1.0a1/benchmarks/README.md +135 -0
- foliq-0.1.0a1/benchmarks/bench/__init__.py +13 -0
- foliq-0.1.0a1/benchmarks/bench/__main__.py +55 -0
- foliq-0.1.0a1/benchmarks/bench/charts.py +126 -0
- foliq-0.1.0a1/benchmarks/bench/datasets.py +187 -0
- foliq-0.1.0a1/benchmarks/bench/libraries.py +214 -0
- foliq-0.1.0a1/benchmarks/bench/parsing.py +178 -0
- foliq-0.1.0a1/benchmarks/bench/scoring.py +55 -0
- foliq-0.1.0a1/benchmarks/bench/search.py +228 -0
- foliq-0.1.0a1/benchmarks/bench/tools.py +114 -0
- foliq-0.1.0a1/benchmarks/bench/worker.py +89 -0
- foliq-0.1.0a1/benchmarks/pyproject.toml +25 -0
- foliq-0.1.0a1/benchmarks/results/quality-dark.svg +3093 -0
- foliq-0.1.0a1/benchmarks/results/quality-docx.json +912 -0
- foliq-0.1.0a1/benchmarks/results/quality-html.json +951 -0
- foliq-0.1.0a1/benchmarks/results/quality-light.svg +3093 -0
- foliq-0.1.0a1/benchmarks/results/quality-pdf.json +573 -0
- foliq-0.1.0a1/benchmarks/results/quality-pptx.json +201 -0
- foliq-0.1.0a1/benchmarks/results/quality-xlsx.json +336 -0
- foliq-0.1.0a1/benchmarks/results/search-quality-dark.svg +1287 -0
- foliq-0.1.0a1/benchmarks/results/search-quality-light.svg +1287 -0
- foliq-0.1.0a1/benchmarks/results/search-scifact.json +42 -0
- foliq-0.1.0a1/benchmarks/results/search-speed-dark.svg +1433 -0
- foliq-0.1.0a1/benchmarks/results/search-speed-light.svg +1433 -0
- foliq-0.1.0a1/benchmarks/results/speed-dark.svg +3013 -0
- foliq-0.1.0a1/benchmarks/results/speed-docx.json +56 -0
- foliq-0.1.0a1/benchmarks/results/speed-light.svg +3013 -0
- foliq-0.1.0a1/benchmarks/results/speed-pdf.json +77 -0
- foliq-0.1.0a1/benchmarks/results/speed-pptx.json +49 -0
- foliq-0.1.0a1/benchmarks/results/speed-xlsx.json +56 -0
- foliq-0.1.0a1/benchmarks/uv.lock +2705 -0
- foliq-0.1.0a1/crates/foliq/Cargo.toml +27 -0
- foliq-0.1.0a1/crates/foliq/examples/custom_parser.rs +46 -0
- foliq-0.1.0a1/crates/foliq/src/index/citation.rs +46 -0
- foliq-0.1.0a1/crates/foliq/src/index/mod.rs +286 -0
- foliq-0.1.0a1/crates/foliq/src/index/reading.rs +297 -0
- foliq-0.1.0a1/crates/foliq/src/index/search.rs +195 -0
- foliq-0.1.0a1/crates/foliq/src/index/sync.rs +281 -0
- foliq-0.1.0a1/crates/foliq/src/lib.rs +17 -0
- foliq-0.1.0a1/crates/foliq/src/markdown.rs +353 -0
- foliq-0.1.0a1/crates/foliq/src/parsers/docx.rs +157 -0
- foliq-0.1.0a1/crates/foliq/src/parsers/html.rs +226 -0
- foliq-0.1.0a1/crates/foliq/src/parsers/markdown.rs +20 -0
- foliq-0.1.0a1/crates/foliq/src/parsers/mod.rs +55 -0
- foliq-0.1.0a1/crates/foliq/src/parsers/office_xml.rs +324 -0
- foliq-0.1.0a1/crates/foliq/src/parsers/pdf.rs +46 -0
- foliq-0.1.0a1/crates/foliq/src/parsers/pptx.rs +166 -0
- foliq-0.1.0a1/crates/foliq/src/parsers/text.rs +19 -0
- foliq-0.1.0a1/crates/foliq/src/parsers/xlsx/formulas.rs +224 -0
- foliq-0.1.0a1/crates/foliq/src/parsers/xlsx/layout.rs +226 -0
- foliq-0.1.0a1/crates/foliq/src/parsers/xlsx/mod.rs +119 -0
- foliq-0.1.0a1/crates/foliq/src/parsers/xlsx/model.rs +321 -0
- foliq-0.1.0a1/crates/foliq/src/parsers/xlsx/read_calamine.rs +112 -0
- foliq-0.1.0a1/crates/foliq/src/parsers/xlsx/read_xlsx.rs +542 -0
- foliq-0.1.0a1/crates/foliq/src/parsers/xlsx/read_xlsx_extras.rs +403 -0
- foliq-0.1.0a1/crates/foliq/src/parsers/xlsx/render.rs +549 -0
- foliq-0.1.0a1/crates/foliq/src/parsers/xlsx/tests.rs +190 -0
- foliq-0.1.0a1/crates/foliq/src/parsers/xlsx/values.rs +174 -0
- foliq-0.1.0a1/crates/foliq/src/sinks/jsonl.rs +43 -0
- foliq-0.1.0a1/crates/foliq/src/sinks/mirror.rs +66 -0
- foliq-0.1.0a1/crates/foliq/src/sinks/mod.rs +12 -0
- foliq-0.1.0a1/crates/foliq/src/sources/folder.rs +106 -0
- foliq-0.1.0a1/crates/foliq/src/sources/mod.rs +19 -0
- foliq-0.1.0a1/crates/foliq/src/splitter.rs +314 -0
- foliq-0.1.0a1/crates/foliq/src/store/mod.rs +5 -0
- foliq-0.1.0a1/crates/foliq/src/store/sqlite.rs +540 -0
- foliq-0.1.0a1/crates/foliq/src/tokens.rs +102 -0
- foliq-0.1.0a1/crates/foliq/tests/index.rs +208 -0
- foliq-0.1.0a1/crates/foliq-cli/Cargo.toml +17 -0
- foliq-0.1.0a1/crates/foliq-cli/SKILL.md +36 -0
- foliq-0.1.0a1/crates/foliq-cli/src/lib.rs +243 -0
- foliq-0.1.0a1/crates/foliq-cli/src/main.rs +6 -0
- foliq-0.1.0a1/crates/foliq-cli/src/output.rs +164 -0
- foliq-0.1.0a1/crates/foliq-core/Cargo.toml +12 -0
- foliq-0.1.0a1/crates/foliq-core/src/chunk.rs +33 -0
- foliq-0.1.0a1/crates/foliq-core/src/document.rs +338 -0
- foliq-0.1.0a1/crates/foliq-core/src/embedder.rs +18 -0
- foliq-0.1.0a1/crates/foliq-core/src/error.rs +57 -0
- foliq-0.1.0a1/crates/foliq-core/src/lib.rs +41 -0
- foliq-0.1.0a1/crates/foliq-core/src/parser.rs +47 -0
- foliq-0.1.0a1/crates/foliq-core/src/sink.rs +34 -0
- foliq-0.1.0a1/crates/foliq-core/src/source.rs +38 -0
- foliq-0.1.0a1/crates/foliq-core/src/splitter.rs +15 -0
- foliq-0.1.0a1/crates/foliq-core/src/store.rs +112 -0
- foliq-0.1.0a1/docs/access.md +33 -0
- foliq-0.1.0a1/docs/agent-tools.md +64 -0
- foliq-0.1.0a1/docs/assets/logo-wordmark-dark.svg +7 -0
- foliq-0.1.0a1/docs/assets/logo-wordmark-light.svg +7 -0
- foliq-0.1.0a1/docs/assets/logo.svg +6 -0
- foliq-0.1.0a1/docs/benchmarks.md +51 -0
- foliq-0.1.0a1/docs/cli.md +58 -0
- foliq-0.1.0a1/docs/formats.md +78 -0
- foliq-0.1.0a1/docs/how-it-works.md +65 -0
- foliq-0.1.0a1/docs/index.md +102 -0
- foliq-0.1.0a1/docs/plugins.md +71 -0
- foliq-0.1.0a1/docs/python.md +58 -0
- foliq-0.1.0a1/prek.toml +38 -0
- foliq-0.1.0a1/pyproject.toml +85 -0
- foliq-0.1.0a1/rustfmt.toml +1 -0
- foliq-0.1.0a1/scripts/cargo-test.sh +16 -0
- foliq-0.1.0a1/scripts/stamp-dev-version.py +47 -0
- foliq-0.1.0a1/src/errors.rs +42 -0
- foliq-0.1.0a1/src/foliq/__init__.py +36 -0
- foliq-0.1.0a1/src/foliq/__main__.py +5 -0
- foliq-0.1.0a1/src/foliq/_cli.py +13 -0
- foliq-0.1.0a1/src/foliq/_core.pyi +172 -0
- foliq-0.1.0a1/src/foliq/plugins.py +70 -0
- foliq-0.1.0a1/src/foliq/py.typed +0 -0
- foliq-0.1.0a1/src/foliq/tools.py +185 -0
- foliq-0.1.0a1/src/json_convert.rs +85 -0
- foliq-0.1.0a1/src/lib.rs +38 -0
- foliq-0.1.0a1/src/python_index.rs +243 -0
- foliq-0.1.0a1/src/python_plugins.rs +256 -0
- foliq-0.1.0a1/tests/conftest.py +22 -0
- foliq-0.1.0a1/tests/fixtures.py +88 -0
- foliq-0.1.0a1/tests/test_cli.py +35 -0
- foliq-0.1.0a1/tests/test_formats.py +47 -0
- foliq-0.1.0a1/tests/test_index.py +124 -0
- foliq-0.1.0a1/uv.lock +915 -0
- foliq-0.1.0a1/zensical.toml +66 -0
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main, dev]
|
|
6
|
+
pull_request:
|
|
7
|
+
workflow_dispatch:
|
|
8
|
+
workflow_call: # release.yml reruns these checks on the tagged commit
|
|
9
|
+
|
|
10
|
+
jobs:
|
|
11
|
+
checks:
|
|
12
|
+
name: Checks and tests (Python ${{ matrix.python-version }})
|
|
13
|
+
runs-on: ubuntu-latest
|
|
14
|
+
strategy:
|
|
15
|
+
fail-fast: false
|
|
16
|
+
matrix:
|
|
17
|
+
python-version: ["3.11", "3.14"]
|
|
18
|
+
steps:
|
|
19
|
+
- uses: actions/checkout@v5
|
|
20
|
+
- uses: dtolnay/rust-toolchain@stable
|
|
21
|
+
with:
|
|
22
|
+
components: rustfmt, clippy
|
|
23
|
+
- uses: Swatinem/rust-cache@v2
|
|
24
|
+
- uses: astral-sh/setup-uv@v7
|
|
25
|
+
with:
|
|
26
|
+
python-version: ${{ matrix.python-version }}
|
|
27
|
+
enable-cache: true
|
|
28
|
+
- run: uv sync --frozen
|
|
29
|
+
# The same hooks developers run on commit and on push (see prek.toml).
|
|
30
|
+
- name: Commit hooks (ruff, cargo fmt, file checks)
|
|
31
|
+
run: uv run --frozen prek run --all-files --show-diff-on-failure
|
|
32
|
+
- name: Push hooks (ty, clippy, cargo test, pytest)
|
|
33
|
+
run: uv run --frozen prek run --all-files --stage pre-push
|
|
34
|
+
|
|
35
|
+
binary:
|
|
36
|
+
name: Standalone binary (${{ matrix.os }})
|
|
37
|
+
runs-on: ${{ matrix.os }}
|
|
38
|
+
strategy:
|
|
39
|
+
fail-fast: false
|
|
40
|
+
matrix:
|
|
41
|
+
os: [macos-latest, windows-latest]
|
|
42
|
+
steps:
|
|
43
|
+
- uses: actions/checkout@v5
|
|
44
|
+
- uses: dtolnay/rust-toolchain@stable
|
|
45
|
+
- uses: Swatinem/rust-cache@v2
|
|
46
|
+
- run: cargo test --locked -p foliq -p foliq-core -p foliq-cli
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
name: Docs
|
|
2
|
+
|
|
3
|
+
# Builds the documentation site (zensical.toml, docs/) and publishes it to GitHub Pages.
|
|
4
|
+
# Needs Settings > Pages > Source: "GitHub Actions".
|
|
5
|
+
on:
|
|
6
|
+
push:
|
|
7
|
+
branches: [main]
|
|
8
|
+
workflow_dispatch:
|
|
9
|
+
|
|
10
|
+
permissions:
|
|
11
|
+
contents: read
|
|
12
|
+
pages: write
|
|
13
|
+
id-token: write
|
|
14
|
+
|
|
15
|
+
concurrency:
|
|
16
|
+
group: pages
|
|
17
|
+
cancel-in-progress: true
|
|
18
|
+
|
|
19
|
+
jobs:
|
|
20
|
+
deploy:
|
|
21
|
+
runs-on: ubuntu-latest
|
|
22
|
+
environment:
|
|
23
|
+
name: github-pages
|
|
24
|
+
url: ${{ steps.deployment.outputs.page_url }}
|
|
25
|
+
steps:
|
|
26
|
+
- uses: actions/checkout@v5
|
|
27
|
+
- uses: astral-sh/setup-uv@v7
|
|
28
|
+
with:
|
|
29
|
+
enable-cache: true
|
|
30
|
+
- uses: actions/configure-pages@v5
|
|
31
|
+
# Only the docs tools: building the site doesn't need the Rust extension.
|
|
32
|
+
- run: uv run --frozen --only-group docs zensical build --clean
|
|
33
|
+
- uses: actions/upload-pages-artifact@v4
|
|
34
|
+
with:
|
|
35
|
+
path: site
|
|
36
|
+
- id: deployment
|
|
37
|
+
uses: actions/deploy-pages@v4
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
name: Release
|
|
2
|
+
|
|
3
|
+
# Every push to main publishes a development build to TestPyPI, like `0.1.0a1.dev42`
|
|
4
|
+
# (the version in Cargo.toml plus `.dev<run number>`, since an index never takes a version twice).
|
|
5
|
+
# Push a tag like `v0.1.0a1` (the Python form of the Cargo.toml version) to publish that version
|
|
6
|
+
# to PyPI and create a GitHub release.
|
|
7
|
+
on:
|
|
8
|
+
push:
|
|
9
|
+
branches: [main]
|
|
10
|
+
tags: ["v*"]
|
|
11
|
+
workflow_dispatch: # the same as a push to main: a development build to TestPyPI
|
|
12
|
+
|
|
13
|
+
permissions:
|
|
14
|
+
contents: read
|
|
15
|
+
|
|
16
|
+
# A newer push to main replaces a development build still in progress; releases always finish.
|
|
17
|
+
concurrency:
|
|
18
|
+
group: release-${{ github.ref }}
|
|
19
|
+
cancel-in-progress: ${{ github.ref_type != 'tag' }}
|
|
20
|
+
|
|
21
|
+
jobs:
|
|
22
|
+
ci:
|
|
23
|
+
name: CI
|
|
24
|
+
uses: ./.github/workflows/ci.yml
|
|
25
|
+
|
|
26
|
+
sdist:
|
|
27
|
+
name: Source distribution
|
|
28
|
+
runs-on: ubuntu-latest
|
|
29
|
+
steps:
|
|
30
|
+
- uses: actions/checkout@v5
|
|
31
|
+
with:
|
|
32
|
+
fetch-depth: 0 # to check that the tag is on main
|
|
33
|
+
- uses: astral-sh/setup-uv@v7
|
|
34
|
+
- name: Check the tag matches the version and is on main
|
|
35
|
+
if: github.ref_type == 'tag'
|
|
36
|
+
run: |
|
|
37
|
+
# Cargo.toml says `0.1.0-alpha.1`; the tag uses the Python form, `v0.1.0a1`.
|
|
38
|
+
version=$(uv run --no-project --with packaging python -c 'import tomllib; from packaging.version import Version; print(Version(tomllib.load(open("Cargo.toml", "rb"))["workspace"]["package"]["version"]))')
|
|
39
|
+
[ "$GITHUB_REF_NAME" = "v$version" ] || { echo "::error::Tag $GITHUB_REF_NAME but Cargo.toml says $version"; exit 1; }
|
|
40
|
+
git merge-base --is-ancestor "$GITHUB_SHA" origin/main || { echo "::error::$GITHUB_REF_NAME is not on main"; exit 1; }
|
|
41
|
+
- name: Stamp a development version
|
|
42
|
+
if: github.ref_type != 'tag'
|
|
43
|
+
run: uv run --no-project --python 3.12 scripts/stamp-dev-version.py ${{ github.run_number }}
|
|
44
|
+
- uses: PyO3/maturin-action@v1
|
|
45
|
+
with:
|
|
46
|
+
command: sdist
|
|
47
|
+
args: --out dist
|
|
48
|
+
- uses: actions/upload-artifact@v6
|
|
49
|
+
with:
|
|
50
|
+
name: dist-sdist
|
|
51
|
+
path: dist
|
|
52
|
+
|
|
53
|
+
wheels:
|
|
54
|
+
name: Wheel (${{ matrix.target }}, ${{ matrix.runner }} ${{ matrix.manylinux }})
|
|
55
|
+
runs-on: ${{ matrix.runner }}
|
|
56
|
+
strategy:
|
|
57
|
+
matrix:
|
|
58
|
+
# The extension uses the stable ABI (abi3-py311): one wheel per platform covers every CPython >= 3.11.
|
|
59
|
+
include:
|
|
60
|
+
- { runner: ubuntu-latest, target: x86_64, manylinux: auto, smoke: true }
|
|
61
|
+
- { runner: ubuntu-24.04-arm, target: aarch64, manylinux: auto, smoke: true }
|
|
62
|
+
- { runner: ubuntu-latest, target: x86_64, manylinux: musllinux_1_2 }
|
|
63
|
+
- { runner: ubuntu-24.04-arm, target: aarch64, manylinux: musllinux_1_2 }
|
|
64
|
+
- { runner: macos-latest, target: aarch64, smoke: true }
|
|
65
|
+
- { runner: macos-latest, target: x86_64 } # cross-compiled from Apple Silicon
|
|
66
|
+
- { runner: windows-latest, target: x64, smoke: true }
|
|
67
|
+
steps:
|
|
68
|
+
- uses: actions/checkout@v5
|
|
69
|
+
- uses: astral-sh/setup-uv@v7
|
|
70
|
+
- name: Stamp a development version
|
|
71
|
+
if: github.ref_type != 'tag'
|
|
72
|
+
run: uv run --no-project --python 3.12 scripts/stamp-dev-version.py ${{ github.run_number }}
|
|
73
|
+
- uses: PyO3/maturin-action@v1
|
|
74
|
+
with:
|
|
75
|
+
target: ${{ matrix.target }}
|
|
76
|
+
manylinux: ${{ matrix.manylinux }}
|
|
77
|
+
args: --release --locked --strip --out dist
|
|
78
|
+
# Install the wheel on the oldest supported Python, import it and run the CLI.
|
|
79
|
+
- name: Smoke test
|
|
80
|
+
if: matrix.smoke
|
|
81
|
+
shell: bash
|
|
82
|
+
run: |
|
|
83
|
+
uv run --isolated --no-project --python 3.11 --with dist/*.whl python -c "import foliq; print(foliq.__version__)"
|
|
84
|
+
uvx --python 3.11 --from dist/*.whl foliq --version
|
|
85
|
+
- uses: actions/upload-artifact@v6
|
|
86
|
+
with:
|
|
87
|
+
name: dist-${{ strategy.job-index }}
|
|
88
|
+
path: dist
|
|
89
|
+
|
|
90
|
+
pypi:
|
|
91
|
+
name: Publish to PyPI
|
|
92
|
+
if: github.ref_type == 'tag'
|
|
93
|
+
needs: [ci, sdist, wheels]
|
|
94
|
+
runs-on: ubuntu-latest
|
|
95
|
+
environment:
|
|
96
|
+
name: pypi
|
|
97
|
+
url: https://pypi.org/p/foliq
|
|
98
|
+
permissions:
|
|
99
|
+
id-token: write # trusted publishing: no API token anywhere
|
|
100
|
+
steps:
|
|
101
|
+
- uses: actions/download-artifact@v7
|
|
102
|
+
with:
|
|
103
|
+
pattern: dist-*
|
|
104
|
+
path: dist
|
|
105
|
+
merge-multiple: true
|
|
106
|
+
- uses: pypa/gh-action-pypi-publish@release/v1
|
|
107
|
+
|
|
108
|
+
testpypi:
|
|
109
|
+
name: Publish to TestPyPI
|
|
110
|
+
if: github.ref_type != 'tag'
|
|
111
|
+
needs: [ci, sdist, wheels]
|
|
112
|
+
runs-on: ubuntu-latest
|
|
113
|
+
environment:
|
|
114
|
+
name: testpypi
|
|
115
|
+
url: https://test.pypi.org/p/foliq
|
|
116
|
+
permissions:
|
|
117
|
+
id-token: write
|
|
118
|
+
steps:
|
|
119
|
+
- uses: actions/download-artifact@v7
|
|
120
|
+
with:
|
|
121
|
+
pattern: dist-*
|
|
122
|
+
path: dist
|
|
123
|
+
merge-multiple: true
|
|
124
|
+
- uses: pypa/gh-action-pypi-publish@release/v1
|
|
125
|
+
with:
|
|
126
|
+
repository-url: https://test.pypi.org/legacy/
|
|
127
|
+
|
|
128
|
+
github-release:
|
|
129
|
+
name: GitHub release
|
|
130
|
+
needs: pypi
|
|
131
|
+
runs-on: ubuntu-latest
|
|
132
|
+
permissions:
|
|
133
|
+
contents: write
|
|
134
|
+
steps:
|
|
135
|
+
- name: Create the release with generated notes
|
|
136
|
+
env:
|
|
137
|
+
GH_TOKEN: ${{ github.token }}
|
|
138
|
+
GH_REPO: ${{ github.repository }}
|
|
139
|
+
run: |
|
|
140
|
+
flags="--generate-notes --verify-tag"
|
|
141
|
+
if [[ "$GITHUB_REF_NAME" =~ (a|b|rc)[0-9]+$ ]]; then flags+=" --prerelease"; fi
|
|
142
|
+
gh release create "$GITHUB_REF_NAME" $flags
|
foliq-0.1.0a1/.gitignore
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
3.11
|
foliq-0.1.0a1/AGENTS.md
ADDED
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
# Notes for coding agents
|
|
2
|
+
|
|
3
|
+
foliq indexes documents (PDF, Word, PowerPoint, Excel, HTML, Markdown) and lets
|
|
4
|
+
AI agents search, read and cite them. It is a Rust engine with a CLI and a
|
|
5
|
+
Python API. Read this file before changing anything.
|
|
6
|
+
|
|
7
|
+
## Philosophy
|
|
8
|
+
|
|
9
|
+
### 1. Small core, everything pluggable (like pi)
|
|
10
|
+
|
|
11
|
+
foliq is a small engine with sockets, in the spirit of the pi coding agent:
|
|
12
|
+
the core does little, does it fast, and every part can be replaced.
|
|
13
|
+
|
|
14
|
+
- Each socket is one small Rust trait in `crates/foliq-core`: `Source`,
|
|
15
|
+
`Parser`, `Splitter`, `Store`, `Sink` (and `Embedder`, used from 0.2).
|
|
16
|
+
Built-in plugins implement the same traits as user plugins. The engine
|
|
17
|
+
never special-cases a built-in.
|
|
18
|
+
- Every socket can be filled from Rust or from Python. Python classes plug in
|
|
19
|
+
through `foliq.Index(parsers=..., splitter=..., sinks=...)`. Rust plugins
|
|
20
|
+
depend on `foliq-core` only.
|
|
21
|
+
- The `foliq` command runs Rust code only. It never starts Python (like ruff
|
|
22
|
+
or uv). Python plugins work through `import foliq` (like polars).
|
|
23
|
+
- Rust does the heavy work: parsing, splitting, token counting, storage,
|
|
24
|
+
search, sync. Files are parsed in parallel and only changed files are
|
|
25
|
+
re-processed.
|
|
26
|
+
- Start small. Add a feature when someone needs it, as a plugin if it can be
|
|
27
|
+
one. Prefer one obvious way to do each thing. If a change makes the core
|
|
28
|
+
bigger, ask whether it could be a plugin instead.
|
|
29
|
+
|
|
30
|
+
### 2. Clean, organized, consistent code that reads well the first time
|
|
31
|
+
|
|
32
|
+
- Names say what things are, in plain words: `document`, `chunks`,
|
|
33
|
+
`heading_path`, `content_hash`, `is_visible_to`. No abbreviations
|
|
34
|
+
(`doc`, `cfg`, `ctx`, `idx`) and no Rust jargon in names.
|
|
35
|
+
- **Rust must be readable by a Python developer who has never seen Rust.**
|
|
36
|
+
Prefer simple, straight-line code over clever generics, macros, lifetimes
|
|
37
|
+
or iterator chains. When a Rust feature would surprise a Python developer
|
|
38
|
+
(`Option`, `?`, `Arc`, traits, `#[serde(...)]`), add a short comment,
|
|
39
|
+
ideally comparing it to Python.
|
|
40
|
+
- Every file starts with a `//!` comment saying what it does. Every public
|
|
41
|
+
item has a `///` comment. Comments explain *why*, not *what*.
|
|
42
|
+
- One job per file. Module docs list the files of a folder in a small table
|
|
43
|
+
(see `crates/foliq/src/index/mod.rs`).
|
|
44
|
+
- Be consistent: same words for the same things everywhere (a "reference" is
|
|
45
|
+
`collection/path#section`, a "citation" adds `(p4, L10-22)`, a "principal"
|
|
46
|
+
is who is asking). The Python API, the CLI and the Rust API use the same
|
|
47
|
+
names.
|
|
48
|
+
- The same rules apply to Python: small functions, clear names, no magic.
|
|
49
|
+
|
|
50
|
+
## Map
|
|
51
|
+
|
|
52
|
+
| Path | What it is |
|
|
53
|
+
|-----------------------|----------------------------------------------------------------|
|
|
54
|
+
| `crates/foliq-core` | Types (`Document`, `Chunk`...) and plugin traits. Small, stable |
|
|
55
|
+
| `crates/foliq` | The engine: parsers, folder source, splitter, SQLite store, sinks, `Index` |
|
|
56
|
+
| `crates/foliq-cli` | The `foliq` command (`run(args)`), and `SKILL.md` for agents |
|
|
57
|
+
| `src/*.rs` | The Python extension `foliq._core` (PyO3) |
|
|
58
|
+
| `src/foliq` | The Python package: tools for agents, plugin protocols, CLI entry |
|
|
59
|
+
| `tests` | Python tests, with generated DOCX/PPTX/XLSX/PDF fixtures |
|
|
60
|
+
| `benchmarks` | Speed and quality against other libraries, on public corpora (own uv project) |
|
|
61
|
+
| `docs` | The documentation site (Zensical, `zensical.toml`) |
|
|
62
|
+
|
|
63
|
+
## Key ideas
|
|
64
|
+
|
|
65
|
+
- Every format becomes Markdown, the one canonical text of a document.
|
|
66
|
+
Headings, tables and pages (`<!-- page N -->`) are found in that text, and
|
|
67
|
+
everything (elements, sections, chunks) is a byte range of it.
|
|
68
|
+
- Sections are numbered like an outline (`2.3`). References and citations use
|
|
69
|
+
those numbers, so an agent can go from a search hit to the full section.
|
|
70
|
+
- Access rules live on documents (`access`: a list of principals; empty means
|
|
71
|
+
everyone). The store filters before ranking, so results never leak.
|
|
72
|
+
`index.tools(principal=...)` binds the principal; it is never a tool argument.
|
|
73
|
+
- Sync is incremental: version (mtime and size), then content hash, then the
|
|
74
|
+
parser and splitter fingerprints decide what is re-processed. A source that
|
|
75
|
+
can't be listed deletes nothing.
|
|
76
|
+
|
|
77
|
+
## Workflow
|
|
78
|
+
|
|
79
|
+
- Tools: uv, maturin, ruff, ty, pytest, cargo fmt, clippy. Hooks run with prek
|
|
80
|
+
(`prek.toml`): `uv run prek install` once.
|
|
81
|
+
- `uv run pytest` builds the extension and runs the Python tests.
|
|
82
|
+
`scripts/cargo-test.sh --workspace` runs the Rust tests.
|
|
83
|
+
- Tests use real files in temporary folders, built by `tests/fixtures.py`.
|
|
84
|
+
Avoid mocks.
|
|
85
|
+
- Docs: `uv run --only-group docs zensical serve`. Update them with every
|
|
86
|
+
user-facing change. Code examples live in files and are included with
|
|
87
|
+
`--8<--`, so they are compiled and tested.
|
|
88
|
+
- The version lives in one place: `[workspace.package]` in `Cargo.toml`.
|
|
89
|
+
- Releases (`.github/workflows/release.yml`): every push to main publishes a
|
|
90
|
+
development build to TestPyPI (`0.1.0a1.dev42`, stamped by
|
|
91
|
+
`scripts/stamp-dev-version.py`). To publish to PyPI, bump the version with
|
|
92
|
+
`cargo set-version --bump alpha` (or `beta`, `rc`, `release`, `patch`...;
|
|
93
|
+
from `cargo install cargo-edit`), which updates Cargo.toml and Cargo.lock in
|
|
94
|
+
SemVer form (`0.1.0-alpha.2`). Merge to main, then push the tag in Python
|
|
95
|
+
form (`git tag v0.1.0a2 && git push origin v0.1.0a2`).
|
foliq-0.1.0a1/CLAUDE.md
ADDED
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
# Notes for coding agents
|
|
2
|
+
|
|
3
|
+
foliq indexes documents (PDF, Word, PowerPoint, Excel, HTML, Markdown) and lets
|
|
4
|
+
AI agents search, read and cite them. It is a Rust engine with a CLI and a
|
|
5
|
+
Python API. Read this file before changing anything.
|
|
6
|
+
|
|
7
|
+
## Philosophy
|
|
8
|
+
|
|
9
|
+
### 1. Small core, everything pluggable (like pi)
|
|
10
|
+
|
|
11
|
+
foliq is a small engine with sockets, in the spirit of the pi coding agent:
|
|
12
|
+
the core does little, does it fast, and every part can be replaced.
|
|
13
|
+
|
|
14
|
+
- Each socket is one small Rust trait in `crates/foliq-core`: `Source`,
|
|
15
|
+
`Parser`, `Splitter`, `Store`, `Sink` (and `Embedder`, used from 0.2).
|
|
16
|
+
Built-in plugins implement the same traits as user plugins. The engine
|
|
17
|
+
never special-cases a built-in.
|
|
18
|
+
- Every socket can be filled from Rust or from Python. Python classes plug in
|
|
19
|
+
through `foliq.Index(parsers=..., splitter=..., sinks=...)`. Rust plugins
|
|
20
|
+
depend on `foliq-core` only.
|
|
21
|
+
- The `foliq` command runs Rust code only. It never starts Python (like ruff
|
|
22
|
+
or uv). Python plugins work through `import foliq` (like polars).
|
|
23
|
+
- Rust does the heavy work: parsing, splitting, token counting, storage,
|
|
24
|
+
search, sync. Files are parsed in parallel and only changed files are
|
|
25
|
+
re-processed.
|
|
26
|
+
- Start small. Add a feature when someone needs it, as a plugin if it can be
|
|
27
|
+
one. Prefer one obvious way to do each thing. If a change makes the core
|
|
28
|
+
bigger, ask whether it could be a plugin instead.
|
|
29
|
+
|
|
30
|
+
### 2. Clean, organized, consistent code that reads well the first time
|
|
31
|
+
|
|
32
|
+
- Names say what things are, in plain words: `document`, `chunks`,
|
|
33
|
+
`heading_path`, `content_hash`, `is_visible_to`. No abbreviations
|
|
34
|
+
(`doc`, `cfg`, `ctx`, `idx`) and no Rust jargon in names.
|
|
35
|
+
- **Rust must be readable by a Python developer who has never seen Rust.**
|
|
36
|
+
Prefer simple, straight-line code over clever generics, macros, lifetimes
|
|
37
|
+
or iterator chains. When a Rust feature would surprise a Python developer
|
|
38
|
+
(`Option`, `?`, `Arc`, traits, `#[serde(...)]`), add a short comment,
|
|
39
|
+
ideally comparing it to Python.
|
|
40
|
+
- Every file starts with a `//!` comment saying what it does. Every public
|
|
41
|
+
item has a `///` comment. Comments explain *why*, not *what*.
|
|
42
|
+
- One job per file. Module docs list the files of a folder in a small table
|
|
43
|
+
(see `crates/foliq/src/index/mod.rs`).
|
|
44
|
+
- Be consistent: same words for the same things everywhere (a "reference" is
|
|
45
|
+
`collection/path#section`, a "citation" adds `(p4, L10-22)`, a "principal"
|
|
46
|
+
is who is asking). The Python API, the CLI and the Rust API use the same
|
|
47
|
+
names.
|
|
48
|
+
- The same rules apply to Python: small functions, clear names, no magic.
|
|
49
|
+
|
|
50
|
+
## Map
|
|
51
|
+
|
|
52
|
+
| Path | What it is |
|
|
53
|
+
|-----------------------|----------------------------------------------------------------|
|
|
54
|
+
| `crates/foliq-core` | Types (`Document`, `Chunk`...) and plugin traits. Small, stable |
|
|
55
|
+
| `crates/foliq` | The engine: parsers, folder source, splitter, SQLite store, sinks, `Index` |
|
|
56
|
+
| `crates/foliq-cli` | The `foliq` command (`run(args)`), and `SKILL.md` for agents |
|
|
57
|
+
| `src/*.rs` | The Python extension `foliq._core` (PyO3) |
|
|
58
|
+
| `src/foliq` | The Python package: tools for agents, plugin protocols, CLI entry |
|
|
59
|
+
| `tests` | Python tests, with generated DOCX/PPTX/XLSX/PDF fixtures |
|
|
60
|
+
| `benchmarks` | Speed and quality against other libraries, on public corpora (own uv project) |
|
|
61
|
+
| `docs` | The documentation site (Zensical, `zensical.toml`) |
|
|
62
|
+
|
|
63
|
+
## Key ideas
|
|
64
|
+
|
|
65
|
+
- Every format becomes Markdown, the one canonical text of a document.
|
|
66
|
+
Headings, tables and pages (`<!-- page N -->`) are found in that text, and
|
|
67
|
+
everything (elements, sections, chunks) is a byte range of it.
|
|
68
|
+
- Sections are numbered like an outline (`2.3`). References and citations use
|
|
69
|
+
those numbers, so an agent can go from a search hit to the full section.
|
|
70
|
+
- Access rules live on documents (`access`: a list of principals; empty means
|
|
71
|
+
everyone). The store filters before ranking, so results never leak.
|
|
72
|
+
`index.tools(principal=...)` binds the principal; it is never a tool argument.
|
|
73
|
+
- Sync is incremental: version (mtime and size), then content hash, then the
|
|
74
|
+
parser and splitter fingerprints decide what is re-processed. A source that
|
|
75
|
+
can't be listed deletes nothing.
|
|
76
|
+
|
|
77
|
+
## Workflow
|
|
78
|
+
|
|
79
|
+
- Tools: uv, maturin, ruff, ty, pytest, cargo fmt, clippy. Hooks run with prek
|
|
80
|
+
(`prek.toml`): `uv run prek install` once.
|
|
81
|
+
- `uv run pytest` builds the extension and runs the Python tests.
|
|
82
|
+
`scripts/cargo-test.sh --workspace` runs the Rust tests.
|
|
83
|
+
- Tests use real files in temporary folders, built by `tests/fixtures.py`.
|
|
84
|
+
Avoid mocks.
|
|
85
|
+
- Docs: `uv run --only-group docs zensical serve`. Update them with every
|
|
86
|
+
user-facing change. Code examples live in files and are included with
|
|
87
|
+
`--8<--`, so they are compiled and tested.
|
|
88
|
+
- The version lives in one place: `[workspace.package]` in `Cargo.toml`.
|
|
89
|
+
- Releases (`.github/workflows/release.yml`): every push to main publishes a
|
|
90
|
+
development build to TestPyPI (`0.1.0a1.dev42`, stamped by
|
|
91
|
+
`scripts/stamp-dev-version.py`). To publish to PyPI, bump the version with
|
|
92
|
+
`cargo set-version --bump alpha` (or `beta`, `rc`, `release`, `patch`...;
|
|
93
|
+
from `cargo install cargo-edit`), which updates Cargo.toml and Cargo.lock in
|
|
94
|
+
SemVer form (`0.1.0-alpha.2`). Merge to main, then push the tag in Python
|
|
95
|
+
form (`git tag v0.1.0a2 && git push origin v0.1.0a2`).
|