quirework 0.1.0__py3-none-any.whl

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.
Files changed (138) hide show
  1. quirework/__init__.py +3 -0
  2. quirework/__main__.py +3 -0
  3. quirework/cli.py +431 -0
  4. quirework/core/__init__.py +1 -0
  5. quirework/core/artifact_paths.py +86 -0
  6. quirework/core/checks.py +235 -0
  7. quirework/core/frontmatter.py +83 -0
  8. quirework/core/globs.py +45 -0
  9. quirework/core/pinned.py +169 -0
  10. quirework/core/usage.py +604 -0
  11. quirework/delivery/__init__.py +1 -0
  12. quirework/delivery/artifacts.py +210 -0
  13. quirework/delivery/text.py +166 -0
  14. quirework/manuscript/__init__.py +1 -0
  15. quirework/manuscript/backfill.py +1972 -0
  16. quirework/manuscript/editions.py +111 -0
  17. quirework/manuscript/footprint.py +95 -0
  18. quirework/manuscript/formats.py +208 -0
  19. quirework/manuscript/lifecycle.py +191 -0
  20. quirework/manuscript/notes.py +2301 -0
  21. quirework/manuscript/pages.py +284 -0
  22. quirework/manuscript/quarto.py +416 -0
  23. quirework/manuscript/quotes.py +512 -0
  24. quirework/manuscript/rename.py +309 -0
  25. quirework/manuscript/sources.py +286 -0
  26. quirework/manuscript/trail.py +1875 -0
  27. quirework/manuscript/units.py +416 -0
  28. quirework/project.py +645 -0
  29. quirework/provenance/__init__.py +1 -0
  30. quirework/provenance/agyfilter.py +436 -0
  31. quirework/provenance/backup/__init__.py +469 -0
  32. quirework/provenance/backup/base.py +290 -0
  33. quirework/provenance/backup/command.py +107 -0
  34. quirework/provenance/backup/directory.py +142 -0
  35. quirework/provenance/backup/git.py +150 -0
  36. quirework/provenance/backup/rclone.py +153 -0
  37. quirework/provenance/capture/__init__.py +1 -0
  38. quirework/provenance/capture/commands.py +28 -0
  39. quirework/provenance/capture/extract_artifacts.py +110 -0
  40. quirework/provenance/capture/extract_files.py +118 -0
  41. quirework/provenance/capture/fetch_conversation.py +127 -0
  42. quirework/provenance/capture/fetch_gemini.py +149 -0
  43. quirework/provenance/capture/render_transcript.py +126 -0
  44. quirework/provenance/capture/transform.py +22 -0
  45. quirework/provenance/catalog.py +733 -0
  46. quirework/provenance/ccfilter.py +1126 -0
  47. quirework/provenance/codexfilter.py +883 -0
  48. quirework/provenance/coldread.py +1731 -0
  49. quirework/provenance/curate.py +67 -0
  50. quirework/provenance/humaninput.py +811 -0
  51. quirework/provenance/ingest.py +31 -0
  52. quirework/provenance/ingestion/__init__.py +1 -0
  53. quirework/provenance/ingestion/agy.py +192 -0
  54. quirework/provenance/ingestion/claude.py +493 -0
  55. quirework/provenance/ingestion/codex.py +296 -0
  56. quirework/provenance/lineage.py +148 -0
  57. quirework/provenance/metrics.py +1247 -0
  58. quirework/provenance/rulings.py +478 -0
  59. quirework/provenance/scope.py +73 -0
  60. quirework/provenance/search.py +455 -0
  61. quirework/provenance/semantic.py +475 -0
  62. quirework/provenance/show.py +1213 -0
  63. quirework/provenance/store.py +1271 -0
  64. quirework/provenance/trees.py +133 -0
  65. quirework/provenance/worktrees.py +199 -0
  66. quirework/providers/__init__.py +1 -0
  67. quirework/providers/blind.py +2192 -0
  68. quirework/providers/canary.py +685 -0
  69. quirework/providers/catalog.py +44 -0
  70. quirework/providers/claude_login.py +92 -0
  71. quirework/providers/exits.py +196 -0
  72. quirework/providers/harness.py +830 -0
  73. quirework/providers/images.py +92 -0
  74. quirework/providers/models.py +1284 -0
  75. quirework/providers/quota.py +588 -0
  76. quirework/providers/reads.py +474 -0
  77. quirework/providers/replies.py +175 -0
  78. quirework/publish/__init__.py +1 -0
  79. quirework/publish/backends.py +112 -0
  80. quirework/publish/bookstage.py +1086 -0
  81. quirework/publish/build.py +60 -0
  82. quirework/publish/editions.py +48 -0
  83. quirework/publish/epubcheck.py +287 -0
  84. quirework/publish/experiment.py +1097 -0
  85. quirework/publish/figfonts.py +234 -0
  86. quirework/publish/fignumbers.py +293 -0
  87. quirework/publish/figures.py +729 -0
  88. quirework/publish/folios.py +62 -0
  89. quirework/publish/fonts.py +307 -0
  90. quirework/publish/graybuild.py +73 -0
  91. quirework/publish/hugo.py +117 -0
  92. quirework/publish/kindle.js +411 -0
  93. quirework/publish/kindle.py +1393 -0
  94. quirework/publish/panelkit.py +918 -0
  95. quirework/publish/plans.py +651 -0
  96. quirework/publish/proof.py +792 -0
  97. quirework/publish/redpen.py +1654 -0
  98. quirework/publish/render.py +942 -0
  99. quirework/publish/targets.py +216 -0
  100. quirework/publish/variant.py +918 -0
  101. quirework/runs/__init__.py +1 -0
  102. quirework/runs/__main__.py +15 -0
  103. quirework/runs/commands.py +278 -0
  104. quirework/runs/coverage.py +86 -0
  105. quirework/runs/engine.py +2143 -0
  106. quirework/runs/feed.py +853 -0
  107. quirework/runs/observe.py +379 -0
  108. quirework/runs/storage.py +155 -0
  109. quirework/settings.py +492 -0
  110. quirework/sops/__init__.py +1 -0
  111. quirework/sops/catalog.py +386 -0
  112. quirework/sops/commands.py +567 -0
  113. quirework/sops/composition.py +382 -0
  114. quirework/sops/instruments.py +184 -0
  115. quirework/sops/personas.py +296 -0
  116. quirework/sops/review.py +2568 -0
  117. quirework/sops/room.py +2791 -0
  118. quirework/sops/roundtable.py +2578 -0
  119. quirework/sops/sections.py +169 -0
  120. quirework/sops/workshop.py +1629 -0
  121. quirework/templates/backup.toml +39 -0
  122. quirework/templates/book.toml +88 -0
  123. quirework/templates/run.toml +32 -0
  124. quirework/templates/site.toml +90 -0
  125. quirework/templates/tells.toml +64 -0
  126. quirework/templates/terminology.toml +20 -0
  127. quirework/templates/tmpfiles.conf +42 -0
  128. quirework/testing.py +345 -0
  129. quirework/text/__init__.py +1 -0
  130. quirework/text/jargon.py +545 -0
  131. quirework/text/mdwrap.py +1001 -0
  132. quirework/text/tells.py +547 -0
  133. quirework-0.1.0.dist-info/METADATA +444 -0
  134. quirework-0.1.0.dist-info/RECORD +138 -0
  135. quirework-0.1.0.dist-info/WHEEL +5 -0
  136. quirework-0.1.0.dist-info/entry_points.txt +2 -0
  137. quirework-0.1.0.dist-info/licenses/LICENSE +21 -0
  138. quirework-0.1.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,39 @@
1
+ # How this provenance store is backed up. It sits in the store, beside
2
+ # store.toml, and `quirework provenance store backup` reads it; `--help`
3
+ # there says what each driver does. Claude Code deletes its transcripts
4
+ # 30 days after they last changed, and from then on the store holds the
5
+ # only copy of a session, so name at least one target.
6
+ #
7
+ # Each [targets.<name>] table is one destination. The name is yours, and
8
+ # `store backup --target <name>` runs that one alone. Replace the example
9
+ # below with your own, and uncomment any other you want.
10
+
11
+ # rclone copies to any remote `rclone config` has set up: Google Drive,
12
+ # SFTP, S3, or a crypt remote that encrypts before anything leaves the
13
+ # machine. Give every store a folder of its own: a destination that holds
14
+ # another store's files is refused.
15
+ [targets.drive]
16
+ driver = "rclone"
17
+ destination = "remote:quirework-provenance/my-book"
18
+
19
+ # directory copies in plain Python to a path that already exists, such as
20
+ # a mounted share. It never creates that directory, so a share that did
21
+ # not mount is refused instead of being filled on the local disk.
22
+ # [targets.nas]
23
+ # driver = "directory"
24
+ # destination = "/mnt/backup/quirework-provenance/my-book"
25
+
26
+ # git makes the store its own repository and every run a commit. History
27
+ # keeps what the working tree drops, at the cost of disk: a pending capture
28
+ # that grows is committed whole again on each run.
29
+ # [targets.history]
30
+ # driver = "git"
31
+ # remote = "git@example.org:me/my-book-provenance.git"
32
+ # branch = "main"
33
+
34
+ # command runs a script kept at the store's top level, owned by you and
35
+ # writable by nobody else. It gets QUIREWORK_STORE, QUIREWORK_STORE_ID and
36
+ # QUIREWORK_BACKUP_TARGET, and keeps the backup's rules itself.
37
+ # [targets.custom]
38
+ # driver = "command"
39
+ # command = ["backup.sh"]
@@ -0,0 +1,88 @@
1
+ # Copy to quirework.toml at the root of a book written with Quarto.
2
+ # Paths are relative to this file; local overrides go in the ignored
3
+ # quirework.local.toml. Quirework never locates a project from its install.
4
+ # For a site, start from `quirework config template site` instead.
5
+
6
+ # Version of the configuration schema.
7
+ schema = 2
8
+
9
+ [project]
10
+ # A display name for reports and configuration inspection.
11
+ name = "Example Book"
12
+ # Ignored working notes that may be discarded or reorganized freely.
13
+ scratchpad = "scratchpad"
14
+ # Ignored project material that must never be published.
15
+ private = "private"
16
+
17
+ [manuscript]
18
+ # Contains _quarto.yml and the live manuscript sources.
19
+ source = "manuscript"
20
+ # Quarto project file used for reading order.
21
+ quarto = "manuscript/_quarto.yml"
22
+ # The chapter directory inside source; change to match your layout.
23
+ chapters = "manuscript/sections"
24
+ # Optional semantic register if your book uses annotation bindings.
25
+ # spec = "manuscript/sections/_spec.md"
26
+ # With a spec, point each section at the conversations that shaped it.
27
+ # The sidecar points into the private corpus, so it stays private too.
28
+ # spec_trail = "private/spec-trail.md"
29
+ # Backfilling that trail from an existing corpus keeps a ledger of leads.
30
+ # spec_trail_leads = "private/spec-trail-leads"
31
+ # Optional book-wide annotations used by the red-pen review copy.
32
+ # review_notes = "manuscript/sections/_review-notes.md"
33
+ # Reader-facing documents that cite the spec or quote the canon.
34
+ companion_dirs = ["companion"]
35
+ # Working material is never treated as an authority by annotation checks.
36
+ noncanonical_roots = ["scratchpad"]
37
+ # Optional project terminology and formatting policy.
38
+ # chapter_policy = "config/chapters.toml"
39
+
40
+ [publish]
41
+ # Authoritative SVG assets used to materialize render galleries.
42
+ figures = "manuscript/sections/illustrations"
43
+ # Generated output only. Keep this directory out of Git.
44
+ build = "build"
45
+ # Derived editions live outside the canon source tree.
46
+ variants = "variants"
47
+
48
+ [sops]
49
+ # Project-owned procedures and their required-reading catalog.
50
+ root = "procedures"
51
+ catalog = "procedures/catalog.json"
52
+ # Perspectives and questions are separate, independently versioned data.
53
+ personas = "profiles"
54
+ instruments = "questions"
55
+ # The prefix belongs to the book, not to the installed tool.
56
+ skill_prefix = "example-"
57
+
58
+ [provenance]
59
+ # A book can publish and run model plans without a private corpus.
60
+ enabled = false
61
+ # The ledger, committed with the book: which sessions were accepted,
62
+ # which were removed and why, and the catalog built from them.
63
+ # root = "private/provenance"
64
+ # The store that keeps the captured sessions themselves, outside the
65
+ # repository: a name under the provenance home, which provenance.home
66
+ # in ~/.config/quirework/config.toml sets and which is otherwise
67
+ # ~/.local/share/quirework/provenance. Create it with `quirework
68
+ # provenance store init`, and back it up: `quirework config template
69
+ # backup` prints the backup.toml the store reads.
70
+ # store = "my-book"
71
+ # Private redaction rules protect blind analyst copies, not primary data.
72
+ # redaction_policy = "private/redactions.toml"
73
+
74
+ [usage]
75
+ # Which commands and procedures this project runs, and which model
76
+ # seats it launches, recorded on this machine and read back by
77
+ # `quirework usage`. Nothing is sent anywhere, no command arguments are
78
+ # kept, and one shared store across your books is what makes the
79
+ # comparison between them worth anything.
80
+ # enabled = true
81
+ # Omit to share the per-user store under the XDG state tree.
82
+ # store = "~/.local/state/quirework/usage"
83
+
84
+ [runs]
85
+ # Omit to use a separate directory for this project in the XDG state tree.
86
+ # store = "~/private/example-book-runs"
87
+ # Reviewed output may live with the book; raw sessions stay private.
88
+ reviews = ".quirework/reviews"
@@ -0,0 +1,32 @@
1
+ # A deliberately tiny, single-turn model test. Preparation freezes this
2
+ # plan but does not launch it. Starting it invokes the selected provider.
3
+
4
+ # Human-readable purpose recorded with the run.
5
+ title = "Read a fictional note"
6
+
7
+ [[seats]]
8
+ # Stable identity of this independent session within the run.
9
+ id = "reader"
10
+ # Native transport. Select a provider installed and configured locally.
11
+ harness = "codex"
12
+ # An inexpensive model, named by family: preparation resolves it to the
13
+ # newest version the Codex catalog lists and freezes that. A version such
14
+ # as "gpt-5.6-luna" pins the seat instead.
15
+ model = "luna"
16
+ # Low effort keeps this synthetic test small; real work chooses its own.
17
+ effort = "low"
18
+
19
+ [seats.policy]
20
+ # No tool use is permitted in this assignment.
21
+ tools = "none"
22
+ # Require OS-enforced file isolation. Agy supports audited instead.
23
+ filesystem = "enforced"
24
+ # Replace the native base prompt to avoid unnecessary test overhead.
25
+ # Supported by Codex and Claude; omit for providers without this feature.
26
+ system_prompt = "Complete the small supplied task. Answer briefly."
27
+
28
+ [[seats.turns]]
29
+ # Turn order is explicit. A completed turn's answer is immutable.
30
+ id = "one"
31
+ # This is all the test material; no book or source repository is supplied.
32
+ prompt = "A fictional note says the lantern is green. Reply only with the color."
@@ -0,0 +1,90 @@
1
+ # Copy to quirework.toml at the root of a site, such as a Hugo blog.
2
+ # Paths are relative to this file; local overrides go in the ignored
3
+ # quirework.local.toml. Quirework never locates a project from its install.
4
+ # For a book, start from `quirework config template book` instead.
5
+
6
+ # Version of the configuration schema.
7
+ schema = 2
8
+
9
+ [project]
10
+ # A display name for reports and configuration inspection.
11
+ name = "Example Site"
12
+ # Ignored project material that must never be published.
13
+ private = "private"
14
+
15
+ [manuscript]
16
+ # The site's pages are the units of the work.
17
+ format = "pages"
18
+ # The directory the site generator renders.
19
+ source = "content"
20
+ # Each post is a page bundle, content/posts/<slug>/index.md, named by
21
+ # its directory. Name collections instead to make other pages units too.
22
+ pages = "posts/*/index.md"
23
+ # [manuscript.collections.posts]
24
+ # pages = "posts/*/index.md"
25
+ # [manuscript.collections.pages]
26
+ # pages = "*.md"
27
+ # order = "title"
28
+ # What messages call one unit.
29
+ unit_name = "post"
30
+ # Marks live outside the rendered tree, so no reader is ever served them.
31
+ marks = "specs/{slug}/marks.md"
32
+ # What several posts lean on, and what each post commits to on its own.
33
+ spec = "specs/_site.md"
34
+ unit_spec = "specs/{slug}/spec.md"
35
+ # Briefs a post may grow from; `spec units` lists the ones not taken up.
36
+ # ideas = "ideas/*/brief.md"
37
+ # Working material is never treated as an authority by annotation checks.
38
+ noncanonical_roots = ["ideas/"]
39
+ # The frontmatter field a published post's revision is recorded in.
40
+ # revision_field = "lastmod"
41
+ # The sources the posts stand on, and plain-text captures of them.
42
+ # sources = "research/sources.md"
43
+ # source_copies = "research/copies/{slug}.txt"
44
+ # With a spec, point each section at the conversations that shaped it.
45
+ # spec_trail = "private/spec-trail.md"
46
+
47
+ [publish]
48
+ # The site's own configuration decides the render; Quirework builds it
49
+ # into build/site and never into the directory the site deploys from.
50
+ backend = "hugo"
51
+ build = "build"
52
+ # Where hugo.toml lives, when it is not the project root.
53
+ # site = "."
54
+
55
+ [text]
56
+ # Posts one sentence per line, other Markdown at 72 columns, generated
57
+ # trees left alone. The first matching row wins.
58
+ modes = [
59
+ ["content/**/*.md", "sentence"],
60
+ ["public/**", "skip"],
61
+ ["resources/**", "skip"],
62
+ ["build/**", "skip"],
63
+ ["**/*.md", "column"],
64
+ ]
65
+ # Voice rules a machine can hold: `quirework config template terminology`.
66
+ # terminology = "quirework/terms.toml"
67
+
68
+ [sops]
69
+ # Project-owned procedures and their required-reading catalog.
70
+ root = "procedures"
71
+ catalog = "procedures/catalog.json"
72
+ # The prefix belongs to the site, not to the installed tool.
73
+ skill_prefix = "example-"
74
+
75
+ [provenance]
76
+ # A site can publish and run model plans without a private corpus.
77
+ enabled = false
78
+ # The ledger, committed with the site, and the store that keeps the
79
+ # captured sessions outside it, under the provenance home that
80
+ # provenance.home in ~/.config/quirework/config.toml sets. Back the
81
+ # store up: `quirework config template backup` prints the backup.toml
82
+ # it reads.
83
+ # root = "private/provenance"
84
+ # store = "my-site"
85
+
86
+ [usage]
87
+ # Which commands and procedures this project runs, and which model
88
+ # seats it launches, recorded on this machine and read back by
89
+ # `quirework usage`. Nothing is sent anywhere.
90
+ # enabled = true
@@ -0,0 +1,64 @@
1
+ # Example machine-habit policy. Point text.tells_policy at this file.
2
+ #
3
+ # `text tells` reports two kinds of habit a language model leaves in prose
4
+ # it drafted. One is the contrast move, which says what a thing is by
5
+ # saying what it is not; its detectors are built in. The other is the
6
+ # phrases listed below. Both only warn: a phrase your subject needs is not
7
+ # a habit, and the author rules on every hit.
8
+ #
9
+ # The phrases are a dated seed, not a standard. They come from Graphite,
10
+ # "AI Tells" (2026), https://graphite.io/five-percent/research/ai-tells,
11
+ # which compared 10,000 human articles with articles on the same topics
12
+ # from nine models: GPT-4.1, GPT-5, GPT-5.6 Sol, GPT-6 Astra, Claude
13
+ # Opus 4, 4.6 and 5, and Gemini 2.5 Pro and 3.1 Pro. Its measurements are
14
+ # CC BY 4.0, so keep this attribution with any list derived from them.
15
+ # Tells shift between model versions (only 45% carried over between two
16
+ # successive GPT releases), so this list ages with the models that draft
17
+ # your prose, and an empty warning from a stale list proves nothing.
18
+ #
19
+ # To refresh it, for the models that draft your prose:
20
+ # 1. Take a measurement of each phrase's rate in model and in human
21
+ # writing on the same topics. The study publishes one; a newer study
22
+ # or a paired sample of your own will do.
23
+ # 2. Keep a phrase when a drafting model uses it at least ten times as
24
+ # often as human writers, across at least a hundred of that model's
25
+ # documents, so that a rare phrase cannot qualify by chance.
26
+ # 3. Count it in your own prose, and keep it only where it occurs more
27
+ # than once, in more than one unit.
28
+ # 4. Read every hit in context before keeping the rule.
29
+ # 5. Record the date and the models here.
30
+ # Phrases readers already associate with machines, such as "delve" or
31
+ # "tapestry", have faded from newer models' output and no longer pass
32
+ # step 2. A project may list them anyway, on the grounds of what its
33
+ # readers believe; say so in the reason.
34
+
35
+ # Pairs of project-relative directory and filename glob to inspect.
36
+ scope_glob = [["manuscript", "*.qmd"]]
37
+ # Basenames in a different register can be excluded deliberately.
38
+ exclude_names = ["sources.qmd"]
39
+ # The contrast detectors are English. Set false for prose in another
40
+ # language, and keep only the phrases.
41
+ contrast = true
42
+
43
+ # Each case-insensitive regular expression, matched one sentence at a time,
44
+ # maps to why it reads as machine-made. `^` anchors at the sentence start.
45
+ # Write a phrase uncontracted, as a model writes it: it also matches the
46
+ # sentence with its contractions spelled out, so "is the whole" finds
47
+ # "that's the whole".
48
+ # Seeded 2026 from the study above; the multiples are against human writing.
49
+ [phrases]
50
+ "\\brather than\\b" = "the connective GPT-6 Astra and Claude Opus 5 overuse most, about 20 times the human rate"
51
+ "\\bnot (?:simply|merely|just) (?:a|an|the|about|that)\\b" = "GPT's corrective intensifier, up to 150 times the human rate; say what the thing is"
52
+ "\\bsingle most\\b" = "a Claude and Gemini superlative; rank only what the argument ranks"
53
+ "\\bless (?:like|as) (?:an? |the )?\\w+(?: \\w+)? (?:and more|than)\\b" = "Claude Opus 5's 'less like X and more like Y' frame"
54
+ "\\bgenuine(?:ly)?\\b" = "Claude's intensifier; it asserts what the sentence should show"
55
+ "\\bthe honest\\b" = "Claude Opus 5 claims candor instead of showing it"
56
+ "\\bquietly\\b" = "Claude Opus 5's adverb for undramatic change; name the change"
57
+ "\\bneed not\\b" = "GPT-6 Astra's corrective hedge; say what does happen"
58
+ "\\bfurthermore\\b" = "Gemini's formal transition"
59
+ "\\btaken together\\b" = "a summarizing turn from Claude Opus 5 and GPT-6 Astra"
60
+ "\\brather than treating\\b|\\bthan treating\\b" = "GPT's corrective setup, almost absent from human writing"
61
+ "\\bit(?: is|'s) worth \\w+ing\\b" = "announces that something deserves attention instead of giving it"
62
+ "^none of (?:this|that)\\b" = "a summarizing pivot at the turn of a paragraph"
63
+ "\\b(?:matters|mattered) (?:enormously|because)\\b|\\bdistinction matters\\b" = "justifies a point by announcing that it matters; show why"
64
+ "\\bearns? its (?:place|keep)\\b|\\bexactly the kind\\b|\\bthe practical takeaway\\b" = "Claude Opus 5 phrasings almost absent from human writing"
@@ -0,0 +1,20 @@
1
+ # Example advisory terminology policy. Point text.terminology at this file.
2
+
3
+ # Pairs of project-relative directory and filename glob to inspect.
4
+ scope_glob = [["manuscript", "*.qmd"]]
5
+ # Explicit exceptions are path suffix, nearby text, and rationale triples.
6
+ allow = []
7
+ # Basenames in a different register can be excluded deliberately.
8
+ exclude_names = ["sources.qmd"]
9
+
10
+ # Each regular expression maps to a plain alternative. These findings
11
+ # invite judgment; the tool never replaces a word automatically.
12
+ [terms]
13
+ "utili[sz]e" = "use"
14
+
15
+ # Phrases the project has retired, each mapped to what replaced it. Unlike
16
+ # terms these gate: `text check` fails while one is in reader-facing prose,
17
+ # headings and tables included, and only an `allow` keep excuses a use.
18
+ # Each is matched as written, in any case and across a line break.
19
+ [retired]
20
+ # "old coinage" = "the plain phrase that replaced it"
@@ -0,0 +1,42 @@
1
+ # Quirework cache cleanup, for systemd-tmpfiles.
2
+ #
3
+ # Nothing empties the XDG cache directory on its own. The specification
4
+ # permits deleting cached data at any time but obliges no one to do it, and a
5
+ # stock Linux system ships no cleaner for it, which is why a working machine's
6
+ # ~/.cache grows without bound. This rule is how a directory under it becomes
7
+ # collectible: systemd-tmpfiles-clean.timer runs daily in the user session and
8
+ # applies whatever it finds here.
9
+ #
10
+ # Install it, and optionally apply it at once rather than waiting for the
11
+ # timer:
12
+ #
13
+ # quirework config template tmpfiles \
14
+ # --out ~/.config/user-tmpfiles.d/quirework.conf
15
+ # systemd-tmpfiles --user --clean
16
+ #
17
+ # A distribution package puts the same file in
18
+ # /usr/share/user-tmpfiles.d/quirework.conf instead, where a user's own copy
19
+ # in ~/.config still overrides it.
20
+ #
21
+ # Everything Quirework keeps in the cache is derived: downloaded tools such as
22
+ # an EPUB validator, redacted renderings, staging for an analysis. Losing any
23
+ # of it costs a rebuild, never a result. Run records are deliberately NOT here
24
+ # -- they are evidence, they live under the XDG state directory, and no rule
25
+ # in this file should ever reach them.
26
+ #
27
+ # The private runner homes of confined seats live here too, under homes/, so
28
+ # a finished run's home goes with the rest. A run left untouched for the whole
29
+ # age loses its homes the same way; it then refuses to resume a session and
30
+ # says the cache was cleared, and its records are untouched. The `x` line
31
+ # keeps the tag that tells backup tools to skip the homes, which nothing
32
+ # rewrites until the next seat launches.
33
+ #
34
+ # `e` cleans the contents of a directory that already exists and never creates
35
+ # one, so this stays inert until Quirework has cached something. An entry is
36
+ # removed only when its access, modification and status times are all older
37
+ # than the age, so a project you are still working in keeps its cache and an
38
+ # abandoned one does not.
39
+ #
40
+ # Type Path Mode User Group Age
41
+ e %C/quirework - - - 30d
42
+ x %C/quirework/homes/CACHEDIR.TAG