my-bucket· 87 objects · 14.2 GBlive
ObjectSizePipelines
contract-v3.pdfnew
184 KB
embed
invoice-q3.pdf
92 KB
embed
policy-2026.docx
210 KB
embed
logos/hero.png
44 KB
ocrembed
audio/q3-call.mp3
12.4 MB
transcribe
data/sales.csvnew
3.2 MB
analytics
logs/2026-05-21.json
1.1 MB
analytics
Ingest rules
**/*.pdfembed
18
**/*.csvanalytics
4
logos/*.pngocr + embed
6
audio/**transcribe
2
Activity
13:42:01contract-v3.pdf embed
13:41:48data/sales.csv analytics
13:40:55audio/q3-call.mp3 transcribe
13:39:32logos/hero.png ocr + embed
region: uk-london-1·auth: SigV4 + JWTK3Service v1
Storage · K3 Objects

S3 that understands your data.

Wire-compatible with S3 — swap the endpoint, keep your SDK. Attach ingest rules and every upload runs your code: embeddings, tables, graphs, all written automatically as the bytes land.

S3-compatible — swap the endpoint

Drop in. Don't rewrite.

Every K3 Objects bucket speaks S3 wire protocol. Point boto3, aws-cli, terraform, rclone — anything — at s3.api.dodil.io and it works unchanged.

put · model-7b.safetensors
# same wire, different host
$ export AWS_ENDPOINT_URL=https://s3.api.dodil.io
$ aws s3 cp model-7b.safetensors s3://my-bucket/models/
upload: ./model-7b.safetensors to s3://my-bucket/models/model-7b.safetensors
14.2 GiB · 204.8 MiB/s · 69s · v4
Installany aws-cli ≥ 2 · just set AWS_ENDPOINT_URLendpoint: s3.api.dodil.io · region: uk | eu
Works unchanged withterraforms3cmdMinIO mcduckdb httpfsrclonersyncCyberduckHugging Face
How a rule fires

Upload to indexed,
in four steps.

No queues to wire, no worker pods to manage. Just rules attached to a bucket, and Scriptum pipelines that fan out from there.

Auto-advancing every 4 s
step 01 · PUT lands+0.00 s

Client sends a signed PUT.

$ aws s3 cp ./contract-v3.pdf \
    s3://my-bucket/docs/contract-v3.pdf
 upload: ./contract-v3.pdf
  to s3://my-bucket/docs/contract-v3.pdf
  184 KB · sha256: 1f0b…3d29 · etag: a1b…
auth
SigV4
region
uk-london-1
tenant
org-1f0b
SigV4 over HTTPS to s3.api.dodil.io. K3 re-signs to the underlying object store per-org. Multi-tenancy is enforced at the proxy layer.
Patterns — built for four payloads

Built for four payloads.

Model weights, RAG corpora, append-only event archives, pinned datasets — one bucket type, four shapes. Versioned, indexed, sovereign.

Model artifacts
Weights, checkpoints, ONNX exports.
my-bucket/models/
model-7b.safetensors14.2 GBv4
tokenizer.json2.1 MBv1
config.json1.4 KBv2
checkpoint-9000.pt26.8 GBv1
Versioned · multipart upload · 200 MB/s+
RAG corpus
Docs → embeddings, automatic.
contract.pdf━━▸match: docs/**━━▸embed → vector
rule rag/index fired · 184 chunks · vectors written to contracts-idx
Scriptum dispatched · vectors indexed
Event archive
Append-only, sealed, retained.
Object-LockCOMPLIANCE
audit-2026-Q2.ndjson · 412 GB
retention 7yunlocks 2033-05-21
WORM-locked · 7y retention · audit-ready
Dataset versioning
Pin training data. Reproduce later.
train-2026-04.parquet4 versions · 86 GB total
v1
2026-01-04
v2
2026-02-11
v3
2026-04-02
📌 PINNED
v4
2026-05-18
Immutable versions · ?versionId= reads
Access control — sovereign by default

S3 auth,
plus tenant isolation.

SigV4 for object operations, Keycloak JWT for the control plane. Every request rides through a tenant gate before policy evaluation — an org-42 token can never read an org-7 key, even if it knows the path.

Private
Org-only · SigV4 with per-org credentials.
default
Public
Anyone with the URL can read. Writes still SigV4.
opt-in
Custom policy
S3-style JSON evaluated per request.
advanced
Auth flow · live tracereq_a8f2…b21e
PUT /my-bucket/uploads/q2-2026.pdf
SigV4 verify
signature · timestamp · key
0.8 ms
Tenant gate
org=acme · jwt sub=svc-uploads
0.4 ms
Policy: bucket/uploads/*
action=s3:PutObject · principal=svc-uploads
1.6 ms
ALLOW
cross-tenant attempts rejected before policy stage
2.8 ms total
Pre-signed URLs — issue, share, expire

Share one file. Five-minute window.

Hand a single object out to a browser, a teammate, or a webhook caller without provisioning IAM. URLs expire on a timer you set and carry scope (GET or PUT) baked in.

Generate
One CLI call, one signed URL.
# issue a 5-minute GET URL
$ dodil objects sign \
my-bucket/reports/q2-2026.pdf \
--method=GET --expires=5m
# or PUT for direct browser upload
$ dodil objects sign \
my-bucket/uploads/$(uuidgen) \
--method=PUT --expires=15m --max-size=25MB
GETPUTmax-sizecontent-typeip-pin
Signed URLexpires in 4:47
https://s3.api.dodil.io/my-bucket/reports/q2-2026.pdf
?X-Sig=9f4c…b21e&X-Exp=1747813620&X-Method=GET
# anyone with the URL can fetch — no creds
$ curl -L "$URL" > q2-2026.pdf
# or upload from the browser
await fetch(url, { method: "PUT", body: file });
scope: one keyexpiry: hard timerno IAM neededHMAC-SHA256
Pricing
47.2MB / s· last 30 s
ingesting
142 PUTs / min
18 rules firing
UK + EU regions
$0.0199
/ GB · month
Stored objects · 14% under S3 Standard
Free
PUT · GET · LIST · pipelines
Pay only for downstream compute
See pricing
Why K3?

Three layers, one RAG system.

K3 = Knowledge 3. Every bucket exposes the same source of truth three ways — objects, structured tables, and embeddings — and the three combined are a production-ready retrieval-augmented generation system out of the box. One bucket. One query. Every layer.

Query
"find the indemnity clause in last quarter's contracts"
01
Vectors
top-5 chunks
what it means
02soon
Tables
rows · filter
what's in it
03
Objects
1 source doc
where it came from
LLM
Answer with citations.
any model · OpenAI-compatible
What you don't have to build:vector ingestion pipelineembedding model wiringschema extractionmetadata DBprovenance trackingfreshness sync
FAQ

Questions, answered.

Smarter than a blob.
Cheaper than S3.

Swap the endpoint. Drop a file. Watch your bucket index itself.

Start free
Regions
UKLiveEULiveMiddle EastSoonAfricaSoon
Compliance
SOC 2In progressISO 27001In progressGDPR-readyData residencyEnforced
© 2026 Circle Technologies Pte Ltd. All rights reserved.