intake: several configured intake channels (mcp, folder, command) all end in quarantine/ (was mcp-upload/), and upload collect pulls the synced-folder and command channels into it (#213); 10.0.0-beta.11
Files changed: - .gitignore - CHANGES.md - VERSION - docs/explanation/architecture.md - docs/explanation/pipeline-rationale.md - docs/how-to/README.md - docs/how-to/back-up-to-a-synced-folder.md - docs/how-to/collect-from-a-synced-folder.md - docs/how-to/ingest-a-source.md - docs/how-to/set-up-the-mcp-server.md - docs/reference/commands/README.md - docs/reference/commands/git.md - docs/reference/commands/instance-health.md - docs/reference/commands/raw-material-and-uploads.md - docs/reference/configuration.md - instructions/gates.md - instructions/ingest-queue.md - instructions/mcp-read-server.md - instructions/migrations/10.0.0-settings-tiers.md - instructions/wiki-ingest/SKILL.md - raw/CONTRACT.md - tools/CONTRACT.md - tools/README.md - tools/chemenu/cli_contract.py - tools/chemenu/collect.py - tools/chemenu/commands/backup_cmd.py - tools/chemenu/commands/docs_verify.py - tools/chemenu/commands/doctor.py - tools/chemenu/commands/raw/pending.py - tools/chemenu/commands/upload_cmd.py - tools/chemenu/config.py - tools/chemenu/config_shapes.py - tools/chemenu/legacy_settings.py - tools/chemenu/mcp/server.py - tools/chemenu/reference_doc.py - tools/chemenu/tests/test_backup.py - tools/chemenu/tests/test_collect.py - tools/chemenu/tests/test_config_shapes.py - tools/chemenu/tests/test_doctor.py - tools/chemenu/tests/test_legacy_settings.py - tools/chemenu/tests/test_mcp_server.py - tools/chemenu/tests/test_upload.py - tools/chemenu/tests/test_upload_cmd.py - tools/chemenu/upload.py Co-Authored-By: Claude Code <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01SnAJ7Z3CpVD3PRbN73QtU2
This commit is contained in:
1 parent
3627168403
commit
cceb9a7bfe
44 files changed
+1910
-346
No files matched your search
@@ -0,0 +1,133 @@
|
||||
# Collect documents from a synced folder
|
||||
|
||||
Documents that are not typed or fetched at this terminal can reach the wiki through an intake
|
||||
channel. Besides the MCP `submit` tool there are two channels that this checkout *pulls* from: a
|
||||
folder that a sync client such as OneDrive fills (handler `folder`), and a program of your own
|
||||
(handler `command`). Both end in the quarantine `quarantine/`, exactly like a submission through the
|
||||
server, and both wait there for a human to run `wikitool upload accept` - the Upload Review Gate
|
||||
stands between every channel and `incoming/`.
|
||||
|
||||
This guide creates a `folder` channel, explains what `upload collect` leaves alone and why, and shows
|
||||
a `command` channel with an example script. The field reference is in the
|
||||
[configuration reference](../reference/configuration.md#intake-channels); the review is in
|
||||
[ingesting a source](ingest-a-source.md#a-document-submitted-from-outside).
|
||||
|
||||
<!-- wikitool:toc -->
|
||||
## Contents
|
||||
|
||||
- [Create the folder channel](#create-the-folder-channel)
|
||||
- [What stays in the folder, and why](#what-stays-in-the-folder-and-why)
|
||||
- [`settle_seconds` and what it cannot promise](#settle_seconds-and-what-it-cannot-promise)
|
||||
- [Deleting in a synced folder deletes everywhere](#deleting-in-a-synced-folder-deletes-everywhere)
|
||||
- [A command channel](#a-command-channel)
|
||||
- [Afterwards](#afterwards)
|
||||
<!-- /wikitool:toc -->
|
||||
|
||||
## Create the folder channel
|
||||
|
||||
Channels are not written by `config set`: every field of the `intake` section opens a path into the
|
||||
checkout, so it is yours to edit by hand in `.wikitool-local.json`.
|
||||
|
||||
```json
|
||||
{
|
||||
"intake": {
|
||||
"channels": {
|
||||
"onedrive": {
|
||||
"handler": "folder",
|
||||
"path": "/home/you/OneDrive/wiki-inbox",
|
||||
"settle_seconds": 60,
|
||||
"max_bytes": 10485760,
|
||||
"allowed_extensions": [".pdf", ".docx", ".md", ".txt"]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
`path` has to be absolute and lie outside the instance. Check it with `tools/wikitool doctor`, then
|
||||
pull:
|
||||
|
||||
```bash
|
||||
tools/wikitool upload collect # every pull channel
|
||||
tools/wikitool upload collect onedrive # only this one
|
||||
tools/wikitool upload list
|
||||
```
|
||||
|
||||
A collected file is stored unchanged in `quarantine/<id>/` with a manifest that names the channel,
|
||||
the handler and the original path. A folder knows nobody who dropped a file, so the submitter is
|
||||
recorded as `unknown`, with the handler as its source: do not trust the name or content of such a
|
||||
file any more than that of a stranger's.
|
||||
|
||||
## What stays in the folder, and why
|
||||
|
||||
`upload collect` reads the top level of the folder only, and it removes one kind of thing: a file it
|
||||
has just stored. Everything else stays where it is and is reported with its reason:
|
||||
|
||||
| Entry | Why it stays |
|
||||
|---|---|
|
||||
| A subdirectory | Nothing descends into it, and nothing deletes a directory. |
|
||||
| A name starting with `.` or `~$`, a hidden or system file | Editors and sync clients keep temporary files like these next to the real one. |
|
||||
| A symbolic link | Following it could leave the folder. |
|
||||
| An extension outside `allowed_extensions`, or a file above `max_bytes` | The same limits as for `submit`. |
|
||||
| A file younger than `settle_seconds` | It may still be arriving. |
|
||||
| A file that changed while it was being read or copied | The source is removed only if it still has the size and sha256 that were stored. |
|
||||
|
||||
A file whose sha256 already waits in the quarantine is reported as a duplicate, with the id of the
|
||||
existing submission, and is removed from the folder.
|
||||
|
||||
## `settle_seconds` and what it cannot promise
|
||||
|
||||
A sync client writes a file in pieces, so a file that is half there looks like a complete, smaller
|
||||
one. `settle_seconds` (default 60) skips files whose modification or creation time is younger than
|
||||
that, and the check that the source did not change during the copy catches the rest. Neither can see
|
||||
a client that pauses for longer than the interval in the middle of a file and then resumes: such a
|
||||
file is stored incomplete, and the review is where you notice it. Raise the value if your client
|
||||
works over a slow link.
|
||||
|
||||
## Deleting in a synced folder deletes everywhere
|
||||
|
||||
A file removed from a folder that OneDrive syncs is removed on every device that syncs it. That is
|
||||
what a collected file should do - it is now in the quarantine - but it also means a collect on one
|
||||
machine empties the folder for all of them. The client's recycle bin keeps the file for a while; the
|
||||
quarantine copy, which is never synced, is the one to rely on. Collect from one machine only.
|
||||
|
||||
## A command channel
|
||||
|
||||
A `command` channel runs a program of your own, which fetches documents from somewhere that has no
|
||||
synced folder - a mailbox, a share, a scanner. The program is named in `commands` and referenced from
|
||||
the channel; the section stays valid only if every reference resolves.
|
||||
|
||||
```json
|
||||
{
|
||||
"intake": {
|
||||
"commands": {
|
||||
"scan-mail": ["/home/you/bin/fetch-attachments.sh"]
|
||||
},
|
||||
"channels": {
|
||||
"mail": { "handler": "command", "command": "scan-mail" }
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
The program is started without a shell and with stdin closed, with an empty staging directory under
|
||||
`quarantine/.staging/` appended as its last argument. It has 300 seconds. It leaves the files it
|
||||
wants to hand over directly in that directory:
|
||||
|
||||
```bash
|
||||
#!/bin/sh
|
||||
# fetch-attachments.sh <staging-dir>
|
||||
set -eu
|
||||
out="$1"
|
||||
rclone copy remote:wiki-inbox "$out" --max-age 1d
|
||||
```
|
||||
|
||||
A program that exits non-zero, does not start or times out fails its channel: nothing is taken, the
|
||||
staging directory is removed, and the last 2000 characters of its stderr are shown. Other channels
|
||||
still run, and `upload collect` exits 1 if any channel failed. With no pull channel configured it
|
||||
exits 0 with "nothing to collect".
|
||||
|
||||
## Afterwards
|
||||
|
||||
The agent does the same at the start of an ingest when you name no file: `upload collect`, then
|
||||
`upload list`, then a report of what waits. It never runs `upload accept` for you.
|
||||
Reference in new issue
Block a user