feat: initial commit — repo scaffold and v1 scope

Scope settled 2026-07-16: implements portfolio-optimiser-commons
ingest-spec (commons keeps spec authorship), Python 3.10+ stdlib-only
core, security delegated to llm-ingestion-guard at persist gates.
Doors: spec-based ingestion, bundle inbox (md/txt/csv/json/html core,
binary formats behind [extract]), external bundle import.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QeqhJpYQyghASjiJo5EhGg
This commit is contained in:
Kjell Tore Guttormsen 2026-07-16 10:12:59 +02:00
commit 47df0aeb4b
7 changed files with 268 additions and 0 deletions

21
.gitignore vendored Normal file
View file

@ -0,0 +1,21 @@
# Python
__pycache__/
*.py[cod]
.venv/
dist/
build/
*.egg-info/
.pytest_cache/
.mypy_cache/
.ruff_cache/
.coverage
# Environment / local
.env
.env.*
*.local.md
.DS_Store
# Local-only: public remote — never publish session state or internal briefs
/STATE.md
/docs/oppstartsprompt.md

3
CHANGELOG.md Normal file
View file

@ -0,0 +1,3 @@
# Changelog
All notable changes to this project will be documented in this file.

113
CLAUDE.md Normal file
View file

@ -0,0 +1,113 @@
# llm-ingestion-okf
## Context
Shared OKF (Open Knowledge Format) ingestion library. Three entry doors,
one boundary rule:
- **Door A — spec-based ingestion:** implements the normative
`ingest-spec.md` owned by `portfolio-optimiser-commons` (manifest →
`file`/`sql`/`http` connector → deterministic materialization of
`ingest-{id}.md` → index generation; zero model calls). This repo
IMPLEMENTS the spec; commons keeps authorship. Spec changes the library
needs go via commons, never edited locally. The library ships the §11
golden fixtures (byte-exact) that are missing today.
- **Door B — bundle inbox:** converts dropped files to OKF concepts. All
file-type→text extraction lives HERE (the guard is text-only). v1 core:
`md`, `txt`, `csv`, `json`, `html` (stdlib). `pdf`/`docx`/`xlsx` only via
the optional `[extract]` extra; without it those types are rejected
fail-fast.
- **Door C — external bundle import:** third-party OKF bundles are assessed
per concept via the guard's `okf.import_bundle`; only non-rejected concepts
are merged/materialized/indexed here.
**Boundary rule (non-negotiable, zero overlap):** `llm-ingestion-guard`
(pinned `>=0.2,<0.3`) answers "is this content safe to persist?" —
scan/sanitize/quarantine/fail-secure/provenance-stamp. This library is
plumbing: connect source → materialize deterministic OKF bundle → generate
index. Never reimplement security; call the guard at persist gates
(`prepare_input`/`screen_output`, `okf.import_bundle`). When in doubt which
side of the boundary something belongs on: ask the operator.
**Implementation baseline:** the stricter behaviors from
`portfolio-optimiser` (streaming row caps, utf-8-sig, in-memory staging with
pre-mutation collision gate, validated `ingested_at`, typed `IngestError`)
are the library baseline. First consumer: `portfolio-optimiser-claude`.
### Open crossroads: the Node second-brain world (decision deferred)
The OKF second-brain plugins (okr, linkedin-studio, ms-ai-architect, and the
marketplace catalog spec) are deliberately Node/ESM zero-dependency and
cannot consume a Python library directly. okr has documented it does not
want a Python bridge. v1 therefore aligns with the catalog's
`okf-second-brain/spec.md` as a *contract* only and ships no Node code.
Revisit when any of these become true:
1. A second Node consumer needs shared ingestion *code*, not just the
catalog conventions (`okf-check.mjs`/`okf-index.mjs`).
2. okr's doc-conversion layer (docx/pdf/eml/html → md) gets built and
duplicates Door B's extraction logic.
3. The catalog's convention-level alignment proves insufficient to keep
bundle forms interoperable.
### Non-goals (v1)
- `strict-v1` wiki bundle profile (`claude-code-llm-wiki`) — v2 candidate;
requires a configurable bundle contract (types/layers/frontmatter sets/
reserved-file policy as config, not constants).
- Verdict/feedback machinery (method-spec) — stays in consumer repos.
- Embedding/RAG/retrieval layers.
## Stack
Python 3.10+. Package `llm_ingestion_okf` (src layout, hatchling).
**Zero runtime dependencies in the core** (stdlib only, like the guard).
The only permitted future runtime dependency is `llm-ingestion-guard`
(itself zero-dep), added when the first persist gate is implemented.
Binary extraction parsers live behind the `[extract]` extra only.
## Conventions
- Type hints everywhere; `mypy --strict` target.
- Determinism is bit-exact: `ingested_at` is an explicit required argument
(no wall-clock defaults); LF-only output; golden fixtures compared
byte-for-byte.
- No model calls anywhere in the run path.
- Credentials only as env-var *references* resolved at runtime; never in
manifests, logs, or frontmatter.
- Network access requires an explicit per-run opt-in flag; refuse fail-fast
otherwise.
- Conventional Commits: `type(scope): description`.
- English for all code, docs, and commit messages (public repo).
## Commands
- Test: `pytest`
- Lint: `ruff check .` + `ruff format --check .`
- Type check: `mypy --strict src/`
## Workflow
- TDD: no production code without a failing test first.
- This repo is published PUBLICLY (`open/` namespace on Forgejo). `STATE.md`
and `docs/oppstartsprompt.md` are LOCAL-ONLY (gitignored) — never commit
session state or internal briefs. No secrets, sober English prose, no
marketing language.
- After `git commit`: push to Forgejo (`git push origin`) immediately.
Never GitHub.
## Communication patterns
### Linking to local files
When pointing to local files in responses, always use markdown link syntax
with a descriptive name:
- Use `[Human-friendly name](file:///absolute/path)` — never bare
`file:///...` URLs or autolinks `<file://...>`.
- Always use absolute paths. Never `~/` or relative paths.
- For multiple files, render as a bullet list of named markdown links.
Why: bare `file://` URLs only render the first as clickable across multiple
lines. Named markdown links make each entry independently clickable and look
cleaner.

21
LICENSE Normal file
View file

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2026 Kjell Tore Guttormsen
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

60
README.md Normal file
View file

@ -0,0 +1,60 @@
# llm-ingestion-okf
Shared ingestion library for OKF (Open Knowledge Format) bundles.
Status: pre-implementation. This repository currently contains the project
scaffold and scope definition only; no pipeline code has been written yet.
## Planned scope (v1)
The library provides three entry points for getting content into an OKF
bundle:
1. **Spec-based ingestion.** An implementation of the normative ingest
specification owned by `portfolio-optimiser-commons`: manifest →
`file`/`sql`/`http` connector → deterministic materialization of
`ingest-{id}.md` concept files → index generation. Zero model calls in the
run path; output is reproducible byte-for-byte against golden fixtures.
2. **Bundle inbox.** A drop directory where common file types are converted
to OKF concept files. All file-type→text extraction lives in this library:
`md`, `txt`, `csv`, `json`, and `html` are handled by the stdlib core;
`pdf`, `docx`, and `xlsx` require the optional `[extract]` extra and are
rejected fail-fast without it. Extracted text passes the security gate
before anything is persisted.
3. **External bundle import.** Import and merge of third-party OKF bundles:
each concept is assessed via the security gate, and only concepts that
pass are merged, materialized, and linked into the index.
## Boundary: security is delegated
Security is owned by the sibling package
[`llm-ingestion-guard`](https://git.fromaitochitta.com/open/llm-ingestion-pipeline-security)
(pinned `>=0.2,<0.3`). The division is strict:
- **guard** answers "is this content safe to persist?" — scan, sanitize,
quarantine, fail-secure, provenance stamping.
- **this library** does the plumbing — connect a source, materialize a
deterministic OKF bundle, generate the index — and calls the guard at every
persist gate (`prepare_input`/`screen_output` for extracted text,
`okf.import_bundle` for received bundles).
No security functionality is reimplemented here.
## Non-goals (v1)
- The `strict-v1` bundle profile used by `claude-code-llm-wiki` (candidate
for v2; requires a configurable bundle contract).
- A Node/JavaScript port for the OKF second-brain plugin ecosystem, which is
deliberately Node/ESM zero-dependency. See CLAUDE.md for the recorded
decision criteria.
- Verdict/feedback machinery from the method specification (stays in the
consuming repositories).
- Embedding- or retrieval-layer functionality.
## Requirements
Python 3.10+. The core has zero runtime dependencies.
## License
MIT — see [LICENSE](LICENSE).

38
pyproject.toml Normal file
View file

@ -0,0 +1,38 @@
[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"
[project]
name = "llm-ingestion-okf"
version = "0.1.0"
description = "Shared OKF (Open Knowledge Format) ingestion library: spec-based connectors, bundle inbox, and external-bundle import, with security delegated to llm-ingestion-guard."
readme = "README.md"
license = "MIT"
requires-python = ">=3.10"
authors = [{ name = "Kjell Tore Guttormsen" }]
classifiers = [
"Development Status :: 2 - Pre-Alpha",
"Intended Audience :: Developers",
"Operating System :: OS Independent",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.10",
]
# Core stays stdlib-only. The single permitted future runtime dependency is
# llm-ingestion-guard (>=0.2,<0.3), added when the first persist gate lands.
dependencies = []
[project.optional-dependencies]
# Reserved for binary file-type extraction parsers (pdf/docx/xlsx).
# Populated when Door B's binary extraction is implemented.
extract = []
[tool.hatch.build.targets.wheel]
packages = ["src/llm_ingestion_okf"]
[tool.ruff]
line-length = 100
target-version = "py310"
[tool.mypy]
strict = true
python_version = "3.10"

View file

@ -0,0 +1,12 @@
"""Shared OKF (Open Knowledge Format) ingestion library.
Three entry doors: spec-based ingestion (manifest -> connector ->
deterministic materialization -> index), a bundle inbox converting common
file types to OKF concepts, and import of external OKF bundles. Security is
delegated to llm-ingestion-guard at every persist gate.
Pre-implementation: no pipeline code yet. See README.md and CLAUDE.md for
scope and boundaries.
"""
__version__ = "0.1.0"