pstq 0.1.0__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.
Files changed (65) hide show
  1. pstq-0.1.0/.devcontainer/Dockerfile +49 -0
  2. pstq-0.1.0/.devcontainer/devcontainer.json +24 -0
  3. pstq-0.1.0/.editorconfig +19 -0
  4. pstq-0.1.0/.github/workflows/ci.yml +36 -0
  5. pstq-0.1.0/.github/workflows/release.yml +166 -0
  6. pstq-0.1.0/.gitignore +106 -0
  7. pstq-0.1.0/.opencode/skills/pstq/SKILL.md +27 -0
  8. pstq-0.1.0/AGENTS.md +193 -0
  9. pstq-0.1.0/CHANGELOG.md +5 -0
  10. pstq-0.1.0/LICENSE +22 -0
  11. pstq-0.1.0/PKG-INFO +187 -0
  12. pstq-0.1.0/PST Search CLI /342/200/224 Implementation Brief.md" +958 -0
  13. pstq-0.1.0/README.md +168 -0
  14. pstq-0.1.0/backlog/config.yml +17 -0
  15. pstq-0.1.0/backlog/tasks/task-001 - Build-offline-PST-query-CLI.md +28 -0
  16. pstq-0.1.0/backlog/tasks/task-001.01 - Prepare-libpff-reader-integration.md +92 -0
  17. pstq-0.1.0/backlog/tasks/task-001.02 - Benchmark-PST-metadata-traversal-and-snapshots.md +84 -0
  18. pstq-0.1.0/backlog/tasks/task-001.03 - Create-SQLite-full-index-importer.md +79 -0
  19. pstq-0.1.0/backlog/tasks/task-001.04 - Implement-atomic-incremental-synchronization.md +73 -0
  20. pstq-0.1.0/backlog/tasks/task-001.05 - Add-FTS-search-and-message-retrieval-commands.md +120 -0
  21. pstq-0.1.0/backlog/tasks/task-001.06 - Clean-quoted-reply-history-for-indexing.md +79 -0
  22. pstq-0.1.0/backlog/tasks/task-001.07 - Add-thread-reconstruction-command.md +94 -0
  23. pstq-0.1.0/backlog/tasks/task-001.08 - Add-attachment-metadata-and-extraction.md +115 -0
  24. pstq-0.1.0/backlog/tasks/task-001.09 - Finalize-agent-CLI-contract-and-documentation.md +125 -0
  25. pstq-0.1.0/backlog/tasks/task-001.10 - Document-available-PST-query-commands.md +75 -0
  26. pstq-0.1.0/backlog/tasks/task-001.11 - Show-cleaned-body-by-default.md +60 -0
  27. pstq-0.1.0/backlog/tasks/task-001.12 - Render-HTML-bodies-with-image-markers.md +60 -0
  28. pstq-0.1.0/backlog/tasks/task-001.13 - Recover-owner-messages-from-quoted-history.md +90 -0
  29. pstq-0.1.0/backlog/tasks/task-001.14 - Search-recovered-owner-responses.md +94 -0
  30. pstq-0.1.0/backlog/tasks/task-001.15 - Resolve-quoted-CID-images-through-source-attachments.md +76 -0
  31. pstq-0.1.0/backlog/tasks/task-001.16 - Stop-persisting-raw-message-bodies.md +83 -0
  32. pstq-0.1.0/backlog/tasks/task-002 - Fail-snapshot-on-incomplete-traversal.md +75 -0
  33. pstq-0.1.0/backlog/tasks/task-003 - Align-attachment-overwrite-behavior-with-docs.md +78 -0
  34. pstq-0.1.0/backlog/tasks/task-004 - Remove-stray-tracked-test-artifacts.md +89 -0
  35. pstq-0.1.0/backlog/tasks/task-005 - Bound-thread-reconstruction-for-large-archives.md +77 -0
  36. pstq-0.1.0/backlog/tasks/task-006 - Reconcile-pypff-dependency-and-install-docs.md +97 -0
  37. pstq-0.1.0/backlog/tasks/task-007 - Harden-json-error-detection-and-no-command-UX.md +80 -0
  38. pstq-0.1.0/backlog/tasks/task-008 - Incrementally-rebuild-recovered-messages.md +89 -0
  39. pstq-0.1.0/backlog/tasks/task-009 - Simplify-redundant-history-sync-branching.md +94 -0
  40. pstq-0.1.0/backlog/tasks/task-010 - Own-and-distribute-the-libpff-integration.md +72 -0
  41. pstq-0.1.0/backlog/tasks/task-011 - Add-CI-and-PyPI-release-automation.md +66 -0
  42. pstq-0.1.0/backlog/tasks/task-012 - Restore-the-release-quality-gate.md +67 -0
  43. pstq-0.1.0/backlog/tasks/task-013 - Make-metadata-coverage-independent-of-pypff-availability.md +66 -0
  44. pstq-0.1.0/docs/adr/0001-expose-direct-pst-item-lookup.md +29 -0
  45. pstq-0.1.0/docs/adr/0002-use-stock-pypff-traversal-locators.md +32 -0
  46. pstq-0.1.0/docs/adr/0003-reconstruct-threads-from-indexed-relationship-metadata.md +49 -0
  47. pstq-0.1.0/docs/adr/0004-model-quoted-history-as-derived-messages.md +49 -0
  48. pstq-0.1.0/docs/adr/0005-unify-native-and-recovered-message-search.md +44 -0
  49. pstq-0.1.0/docs/code-review-2026-08-29.html +256 -0
  50. pstq-0.1.0/pstq/__init__.py +6 -0
  51. pstq-0.1.0/pstq/body.py +283 -0
  52. pstq-0.1.0/pstq/cli.py +700 -0
  53. pstq-0.1.0/pstq/default_config.yaml +33 -0
  54. pstq-0.1.0/pstq/index.py +2193 -0
  55. pstq-0.1.0/pstq/metadata.py +339 -0
  56. pstq-0.1.0/pstq/pst.py +595 -0
  57. pstq-0.1.0/pstq/pstq.py +11 -0
  58. pstq-0.1.0/pyproject.toml +65 -0
  59. pstq-0.1.0/tests/test_body.py +110 -0
  60. pstq-0.1.0/tests/test_index.py +2071 -0
  61. pstq-0.1.0/tests/test_metadata.py +361 -0
  62. pstq-0.1.0/tests/test_pst.py +660 -0
  63. pstq-0.1.0/tests/test_pstq.py +917 -0
  64. pstq-0.1.0/tox.ini +23 -0
  65. pstq-0.1.0/uv.lock +530 -0
@@ -0,0 +1,49 @@
1
+ FROM python:3.13-slim AS pypff-builder
2
+
3
+ # Build a wheel from the immutable libpff Python source distribution.
4
+ ARG LIBPFF_VERSION=20231205
5
+ ARG LIBPFF_SHA256=06c218be51321b16dc3b835185ee1cd2fa5c2a1ca856e0390c1d6e4ddf329250
6
+
7
+ # Install the native build dependencies in the builder only.
8
+ RUN apt-get update \
9
+ && apt-get install -y --no-install-recommends \
10
+ build-essential \
11
+ ca-certificates \
12
+ curl \
13
+ zlib1g-dev \
14
+ && rm -rf /var/lib/apt/lists/*
15
+
16
+ RUN curl --fail --location --silent --show-error \
17
+ --output /tmp/libpff-python.tar.gz \
18
+ "https://files.pythonhosted.org/packages/0b/a3/826777491832478f5e1555a16bc9de794ef0264eac53d213340dddae5bd4/libpff-python-${LIBPFF_VERSION}.tar.gz" \
19
+ && printf '%s %s\n' "$LIBPFF_SHA256" /tmp/libpff-python.tar.gz \
20
+ | sha256sum --check \
21
+ && python -m pip wheel --no-cache-dir --no-deps \
22
+ --wheel-dir /opt/pypff-wheel /tmp/libpff-python.tar.gz
23
+
24
+ FROM python:3.13-slim
25
+
26
+ COPY --from=pypff-builder /opt/pypff-wheel /tmp/pypff-wheel
27
+
28
+ RUN python -m pip install --no-cache-dir /tmp/pypff-wheel/*.whl \
29
+ && python -c "import pypff" \
30
+ && rm -rf /tmp/pypff-wheel
31
+
32
+ # Install git and other dependencies.
33
+ RUN apt-get update \
34
+ && apt-get install -y --no-install-recommends bash ca-certificates curl git \
35
+ && rm -rf /var/lib/apt/lists/*
36
+
37
+ # Install uv
38
+ RUN pip install uv
39
+
40
+
41
+ # Install Backlog.md
42
+ RUN apt-get update \
43
+ && apt-get install -y --no-install-recommends nodejs npm \
44
+ && npm install -g backlog.md \
45
+ && rm -rf /var/lib/apt/lists/*
46
+
47
+
48
+ # Install OpenCode CLI
49
+ RUN curl -fsSL https://opencode.ai/install | bash
@@ -0,0 +1,24 @@
1
+ {
2
+ "name": "Python 3.13",
3
+ "build": {
4
+ "dockerfile": "Dockerfile"
5
+ },
6
+ "customizations": {
7
+ "vscode": {
8
+ "extensions": [
9
+ "ms-python.python",
10
+ "ms-python.vscode-pylance",
11
+ "charliermarsh.ruff",
12
+ "sst-dev.opencode"
13
+ ]
14
+ }
15
+ },
16
+ "remoteEnv": {
17
+ "OPENCODE_ENABLE_EXA": "true"
18
+ },
19
+ "mounts": [
20
+ "source=${localEnv:HOME}/.config/opencode,target=/root/.config/opencode,type=bind,consistency=cached",
21
+ "source=${localEnv:HOME}/.local/share/opencode,target=/root/.local/share/opencode,type=bind,consistency=cached"
22
+ ],
23
+ "postCreateCommand": "if [ -f .backlog-config.yml ]; then git init && backlog init --defaults --backlog-dir backlog --config-location folder --task-prefix task --zero-padded-ids 3 --check-branches false --include-remote false --branch-days 30 --bypass-git-hooks true --web-port 6420 --auto-open-browser false --integration-mode cli --agent-instructions agents && mv .backlog-config.yml backlog/config.yml; fi && uv venv --clear --system-site-packages && uv sync --group dev && uv run python -c 'import pypff'"
24
+ }
@@ -0,0 +1,19 @@
1
+ # http://editorconfig.org
2
+
3
+ root = true
4
+
5
+ [*]
6
+ indent_style = space
7
+ indent_size = 4
8
+ trim_trailing_whitespace = true
9
+ insert_final_newline = true
10
+ charset = utf-8
11
+ end_of_line = lf
12
+
13
+ [*.bat]
14
+ indent_style = tab
15
+ end_of_line = crlf
16
+
17
+ [LICENSE]
18
+ insert_final_newline = false
19
+
@@ -0,0 +1,36 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches:
6
+ - main
7
+ pull_request:
8
+ branches:
9
+ - main
10
+ workflow_dispatch:
11
+
12
+ permissions:
13
+ contents: read
14
+
15
+ concurrency:
16
+ group: ci-${{ github.workflow }}-${{ github.ref }}
17
+ cancel-in-progress: true
18
+
19
+ jobs:
20
+ quality:
21
+ name: Quality checks
22
+ runs-on: ubuntu-latest
23
+ steps:
24
+ - name: Check out repository
25
+ uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
26
+ with:
27
+ persist-credentials: false
28
+
29
+ - name: Install uv
30
+ uses: astral-sh/setup-uv@20cfd1bf945f4377ade1205e4dbc17946fc9a30d # v10.0.1
31
+ with:
32
+ python-version: "3.13"
33
+ enable-cache: true
34
+
35
+ - name: Run quality checks
36
+ run: uv run tox
@@ -0,0 +1,166 @@
1
+ name: Release
2
+
3
+ on:
4
+ push:
5
+ tags:
6
+ - "v*"
7
+ workflow_dispatch:
8
+ inputs:
9
+ tag:
10
+ description: Existing vX.Y.Z tag to release
11
+ required: true
12
+ type: string
13
+ skip_pypi:
14
+ description: Skip PyPI only when this version is already published
15
+ required: true
16
+ default: false
17
+ type: boolean
18
+
19
+ permissions:
20
+ contents: read
21
+
22
+ concurrency:
23
+ group: release-${{ github.event_name == 'workflow_dispatch' && inputs.tag || github.ref_name }}
24
+ cancel-in-progress: false
25
+
26
+ jobs:
27
+ build:
28
+ name: Validate and build release artifacts
29
+ runs-on: ubuntu-latest
30
+ outputs:
31
+ tag: ${{ steps.release.outputs.tag }}
32
+ steps:
33
+ - name: Check out release tag
34
+ uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
35
+ with:
36
+ ref: ${{ github.event_name == 'workflow_dispatch' && inputs.tag || github.ref }}
37
+ fetch-depth: 0
38
+ persist-credentials: false
39
+
40
+ - name: Validate release version
41
+ id: release
42
+ env:
43
+ RELEASE_TAG: ${{ github.event_name == 'workflow_dispatch' && inputs.tag || github.ref_name }}
44
+ run: |
45
+ set -euo pipefail
46
+ [[ "$RELEASE_TAG" =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]] || {
47
+ echo "Release tag must match vX.Y.Z: $RELEASE_TAG" >&2
48
+ exit 1
49
+ }
50
+ git rev-parse --verify "refs/tags/$RELEASE_TAG" >/dev/null
51
+ python - "$RELEASE_TAG" <<'PY'
52
+ import ast
53
+ import re
54
+ import sys
55
+ import tomllib
56
+
57
+ tag = sys.argv[1]
58
+ with open("pyproject.toml", "rb") as pyproject:
59
+ version = tomllib.load(pyproject)["project"]["version"]
60
+ module = ast.parse(open("pstq/__init__.py", encoding="utf-8").read())
61
+ module_version = next(
62
+ (
63
+ ast.literal_eval(node.value)
64
+ for node in module.body
65
+ if isinstance(node, ast.Assign)
66
+ and any(
67
+ isinstance(target, ast.Name) and target.id == "__version__"
68
+ for target in node.targets
69
+ )
70
+ ),
71
+ None,
72
+ )
73
+ changelog = open("CHANGELOG.md", encoding="utf-8").read()
74
+
75
+ if tag != f"v{version}":
76
+ raise SystemExit(
77
+ f"Release tag {tag!r} does not match package version {version!r}."
78
+ )
79
+ if module_version != version:
80
+ raise SystemExit(
81
+ "pstq.__version__ does not match the package version "
82
+ f"{version!r}."
83
+ )
84
+ if not re.search(rf"^## {re.escape(version)}(?: |$)", changelog, re.MULTILINE):
85
+ raise SystemExit(f"CHANGELOG.md has no heading for version {version!r}.")
86
+ PY
87
+ echo "tag=$RELEASE_TAG" >> "$GITHUB_OUTPUT"
88
+
89
+ - name: Install uv
90
+ uses: astral-sh/setup-uv@20cfd1bf945f4377ade1205e4dbc17946fc9a30d # v10.0.1
91
+ with:
92
+ python-version: "3.13"
93
+
94
+ - name: Install locked development dependencies
95
+ run: uv sync --group dev --locked
96
+
97
+ - name: Run quality checks
98
+ run: uv run tox
99
+
100
+ - name: Build distributions
101
+ run: uv build --out-dir dist --clear
102
+
103
+ - name: Validate distribution metadata
104
+ run: uv tool run twine check dist/*
105
+
106
+ - name: Smoke test the built wheel
107
+ run: |
108
+ uv venv --python 3.13 .release-venv
109
+ uv pip install --python .release-venv/bin/python dist/*.whl
110
+ .release-venv/bin/python - <<'PY'
111
+ import importlib.metadata
112
+ import pstq
113
+
114
+ assert importlib.metadata.version("pstq") == pstq.__version__
115
+ PY
116
+ .release-venv/bin/pstq --help >/dev/null
117
+
118
+ - name: Upload release distributions
119
+ uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
120
+ with:
121
+ name: release-distributions
122
+ path: dist/
123
+ if-no-files-found: error
124
+
125
+ publish-pypi:
126
+ name: Publish to PyPI
127
+ needs: build
128
+ runs-on: ubuntu-latest
129
+ environment:
130
+ name: pypi
131
+ url: https://pypi.org/p/pstq
132
+ permissions:
133
+ id-token: write
134
+ steps:
135
+ - name: Download release distributions
136
+ uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
137
+ with:
138
+ name: release-distributions
139
+ path: dist/
140
+
141
+ - name: Publish package distributions to PyPI
142
+ if: ${{ !inputs.skip_pypi }}
143
+ uses: pypa/gh-action-pypi-publish@dc37677b2e1c63e2034f94d8a5b11f265b73ba33 # v1.14.2
144
+ with:
145
+ packages-dir: dist/
146
+
147
+ create-github-release:
148
+ name: Create GitHub Release
149
+ needs:
150
+ - build
151
+ - publish-pypi
152
+ runs-on: ubuntu-latest
153
+ permissions:
154
+ contents: write
155
+ steps:
156
+ - name: Download release distributions
157
+ uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
158
+ with:
159
+ name: release-distributions
160
+ path: dist/
161
+
162
+ - name: Create GitHub Release
163
+ env:
164
+ GH_TOKEN: ${{ github.token }}
165
+ RELEASE_TAG: ${{ needs.build.outputs.tag }}
166
+ run: gh release create "$RELEASE_TAG" dist/* --verify-tag --generate-notes
pstq-0.1.0/.gitignore ADDED
@@ -0,0 +1,106 @@
1
+ # Byte-compiled / optimized / DLL files
2
+ __pycache__/
3
+ *.py[cod]
4
+ *$py.class
5
+
6
+ # C extensions
7
+ *.so
8
+
9
+ # Distribution / packaging
10
+ .Python
11
+ env/
12
+ build/
13
+ develop-eggs/
14
+ dist/
15
+ downloads/
16
+ eggs/
17
+ .eggs/
18
+ lib/
19
+ lib64/
20
+ parts/
21
+ sdist/
22
+ var/
23
+ wheels/
24
+ *.egg-info/
25
+ .installed.cfg
26
+ *.egg
27
+
28
+ # PyInstaller
29
+ # Usually these files are written by a python script from a template
30
+ # before PyInstaller builds the exe, so as to inject date/other infos into it.
31
+ *.manifest
32
+ *.spec
33
+
34
+ # Installer logs
35
+ pip-log.txt
36
+ pip-delete-this-directory.txt
37
+
38
+ # Unit test / coverage reports
39
+ htmlcov/
40
+ .tox/
41
+ .coverage
42
+ .coverage.*
43
+ .cache
44
+ nosetests.xml
45
+ coverage.xml
46
+ *.cover
47
+ .hypothesis/
48
+ .pytest_cache/
49
+
50
+ # Translations
51
+ *.mo
52
+ *.pot
53
+
54
+ # Django stuff:
55
+ *.log
56
+ local_settings.py
57
+
58
+ # Flask stuff:
59
+ instance/
60
+ .webassets-cache
61
+
62
+ # Scrapy stuff:
63
+ .scrapy
64
+
65
+ # PyBuilder
66
+ target/
67
+
68
+ # Jupyter Notebook
69
+ .ipynb_checkpoints
70
+
71
+ # pyenv
72
+ #.python-version
73
+
74
+ # celery beat schedule file
75
+ celerybeat-schedule
76
+
77
+ # SageMath parsed files
78
+ *.sage.py
79
+
80
+ # dotenv
81
+ .env
82
+
83
+ # virtualenv
84
+ .venv
85
+ venv/
86
+ ENV/
87
+
88
+ # Spyder project settings
89
+ .spyderproject
90
+ .spyproject
91
+
92
+ # Rope project settings
93
+ .ropeproject
94
+
95
+ # mypy
96
+ .mypy_cache/
97
+ alabaster
98
+
99
+ .vscode/
100
+ .idea/
101
+ .claude/
102
+
103
+ # temporary files
104
+ temp/
105
+ test.json
106
+ test_config.yaml
@@ -0,0 +1,27 @@
1
+ ---
2
+ name: pstq
3
+ description: Use when searching, retrieving, threading, or extracting content from an Outlook PST with pstq.
4
+ ---
5
+
6
+ # PST Query
7
+
8
+ Use `pstq` rather than parsing the PST or SQLite database directly. The PST is
9
+ read-only and authoritative; the SQLite index is a disposable local cache.
10
+
11
+ Before issuing an unfamiliar command, read its canonical documentation:
12
+
13
+ ```console
14
+ pstq --help
15
+ pstq <command> --help
16
+ ```
17
+
18
+ Use `--json` for programmatic work. On success it writes deterministic JSON to
19
+ stdout. On failure it writes a JSON error envelope to stderr and returns a
20
+ non-zero exit code. Do not infer JSON fields, ID formats, limits, cache access,
21
+ or synchronization behavior from this skill; command-level `--help` defines
22
+ the current contract.
23
+
24
+ The normal retrieval sequence is `status`, `folders` when needed, bounded
25
+ `search`, then `show` for selected message IDs. Use `thread`, `attachments`,
26
+ and `attachment` only after reading their help. Never modify the configured
27
+ PST or assume it is safe to access while Outlook is writing it.
pstq-0.1.0/AGENTS.md ADDED
@@ -0,0 +1,193 @@
1
+ ## Backlog.md workflow
2
+
3
+ Backlog.md is the authoritative record of active and completed development work.
4
+
5
+ Tasks are living work records. Their initial descriptions and acceptance criteria may be incomplete and may evolve during implementation as the human and agent investigate the problem.
6
+
7
+ ### General rules
8
+
9
+ 1. Before beginning substantial work, identify the relevant Backlog task and read it in full.
10
+ 2. Do not treat the initial task specification as immutable.
11
+ 3. Keep the task synchronized with the current shared understanding throughout the development session.
12
+ 4. Do not require the human to operate the Backlog CLI. Perform all necessary Backlog operations yourself.
13
+ 5. Use Backlog.md tasks, comments, plans, notes, and final summaries.
14
+ 6. Do not use Backlog.md decisions. Record durable architectural decisions as ADRs under `docs/adr/`.
15
+ 7. Only the human may accept a task as complete.
16
+
17
+ ### Comments
18
+
19
+ Use task comments as a concise chronological record of material human-agent discussion.
20
+
21
+ Add comments on behalf of both participants when the conversation produces information that would be useful in a future session, including:
22
+
23
+ * clarification of ambiguous requirements;
24
+ * answers to implementation questions;
25
+ * requested changes in behavior or scope;
26
+ * alternatives considered and rejected;
27
+ * explicit human approvals or objections;
28
+ * reasons for changing the implementation direction;
29
+ * unresolved questions that affect further work.
30
+
31
+ When recording comments:
32
+
33
+ * Attribute each comment clearly as `Human` or `Agent`.
34
+ * A comment attributed to `Human` must faithfully summarize something the human explicitly said or confirmed.
35
+ * Do not invent, extrapolate, or strengthen the human's position.
36
+ * Preserve important qualifications and uncertainty.
37
+ * Prefer concise summaries over verbatim transcripts.
38
+ * Do not record routine conversation, acknowledgements, minor corrections, or raw chat history.
39
+ * Group closely related discussion into one comment when appropriate.
40
+ * Record comments during the session when a material clarification occurs, rather than trying to reconstruct the entire conversation at the end.
41
+
42
+ Example:
43
+
44
+ > **Agent:** The existing importer permits identical entries from different source files. Should duplicate detection apply globally or only within one import?
45
+
46
+ > **Human:** Duplicate detection should apply only within one import process. Identical entries from separate imports are allowed.
47
+
48
+ Comments provide the historical trail, but they are not the canonical specification.
49
+
50
+ ### Updating the canonical task
51
+
52
+ After a question is settled, update the relevant canonical part of the task:
53
+
54
+ * update the description when the intended behavior or scope changes;
55
+ * update acceptance criteria when testable requirements are clarified;
56
+ * update the implementation plan when the technical approach changes;
57
+ * update dependencies when newly discovered work blocks the task.
58
+
59
+ A future agent should be able to understand the current requirements without reconstructing them from comments.
60
+
61
+ Preserve the original intent where useful, but make the current description and acceptance criteria accurately represent the latest agreed behavior.
62
+
63
+ When requirements remain uncertain, state the uncertainty explicitly rather than silently selecting an interpretation.
64
+
65
+ ### Notes
66
+
67
+ Use task notes as durable working memory for implementation-related knowledge discovered during the task.
68
+
69
+ Appropriate notes include:
70
+
71
+ * relevant existing code and where it is located;
72
+ * observed current behavior;
73
+ * investigation results;
74
+ * technical constraints;
75
+ * external API or library behavior relevant to the task;
76
+ * failed approaches and why they failed;
77
+ * commands useful for reproducing or verifying behavior;
78
+ * migration or compatibility concerns;
79
+ * assumptions that still require verification;
80
+ * risks and known limitations;
81
+ * useful context for continuing the task in another agent session.
82
+
83
+ Notes should contain distilled conclusions and evidence, not private reasoning or an exhaustive activity log.
84
+
85
+ Good note:
86
+
87
+ > Duplicate detection cannot use a database unique constraint because users may approve otherwise identical rows. Implement it in `ImportValidationService`, scoped by `ImportProcess.id`.
88
+
89
+ Bad note:
90
+
91
+ > I opened several files, thought about using a constraint, changed my mind, and then considered a service.
92
+
93
+ Keep notes current:
94
+
95
+ * correct notes that are proven wrong;
96
+ * remove or clearly mark obsolete information;
97
+ * preserve failed approaches only when knowing about them prevents repeated work;
98
+ * distinguish confirmed facts from assumptions.
99
+
100
+ ### ADRs
101
+
102
+ Do not create or use Backlog.md decision records.
103
+
104
+ Create an ADR under `docs/adr/` when a decision:
105
+
106
+ * affects multiple tasks or components;
107
+ * defines a long-lived architectural rule;
108
+ * changes an important data model, interface, dependency, or deployment approach;
109
+ * involves meaningful alternatives and trade-offs;
110
+ * is likely to matter after the current task is completed.
111
+
112
+ Use the next available ADR number and the repository's ADR template.
113
+
114
+ A task should link to relevant ADRs, for example:
115
+
116
+ > Architectural context: `docs/adr/0012-store-monetary-values-as-integers.md`
117
+
118
+ Task-specific choices that have no wider architectural significance should remain in the task comments, notes, or implementation plan.
119
+
120
+ ### Scope discovered during implementation
121
+
122
+ Do not silently expand a task.
123
+
124
+ When additional work is discovered:
125
+
126
+ * incorporate it into the active task only when it is small, necessary to satisfy the agreed acceptance criteria, and does not materially broaden the scope;
127
+ * otherwise create a separate Backlog task;
128
+ * link the new task from the active task;
129
+ * state whether it blocks the active task or is follow-up work.
130
+
131
+ ### Session checkpoints
132
+
133
+ Update the Backlog task at natural checkpoints:
134
+
135
+ 1. after initial investigation;
136
+ 2. after a material requirement clarification;
137
+ 3. after a significant change in implementation approach;
138
+ 4. before ending a session with unfinished work;
139
+ 5. before requesting human review.
140
+
141
+ Before ending an unfinished session, ensure that another agent can continue from the task without requiring access to the previous chat.
142
+
143
+ At minimum, record:
144
+
145
+ * the current state of implementation;
146
+ * settled requirements;
147
+ * remaining open questions;
148
+ * relevant findings;
149
+ * the next concrete action;
150
+ * commands or tests needed to continue.
151
+
152
+ ### Completion
153
+
154
+ Before moving a task to human review:
155
+
156
+ 1. Re-read the complete task.
157
+ 2. Ensure the description and acceptance criteria reflect the final agreed scope.
158
+ 3. Ensure all material session decisions are represented in the canonical task, comments, notes, or an ADR.
159
+ 4. Update acceptance-criteria checkboxes based on verified behavior.
160
+ 5. Add a final summary containing:
161
+
162
+ * what changed;
163
+ * important implementation choices;
164
+ * tests and checks performed;
165
+ * known limitations;
166
+ * follow-up tasks;
167
+ * ADRs created or referenced.
168
+ 6. Move the task to the review state, not directly to accepted or complete.
169
+ 7. Leave final acceptance to the human.
170
+
171
+ <!-- BACKLOG.MD GUIDELINES START -->
172
+ <!-- backlog.md-instructions-version: 1.50.1 -->
173
+ <CRITICAL_INSTRUCTION>
174
+
175
+ ## Backlog.md Workflow
176
+
177
+ This project uses Backlog.md for task and project management.
178
+
179
+ **For every user request in this project, run `backlog instructions overview` before answering or taking action.**
180
+
181
+ Use the overview to decide whether to search, read, create, or update Backlog tasks.
182
+
183
+ Before task lifecycle actions, read the matching detailed guide:
184
+ - `backlog instructions task-creation` before creating or splitting tasks
185
+ - `backlog instructions task-execution` before planning, changing status or assignee, adding a plan or implementation notes, or implementing task work
186
+ - `backlog instructions task-finalization` before checking acceptance criteria, writing final summaries, or moving tasks to terminal statuses
187
+
188
+ Use `backlog <command> --help` before running unfamiliar commands. Help shows options, fields, and examples.
189
+
190
+ Do not edit Backlog task, draft, document, decision, or milestone markdown files directly. Use the `backlog` CLI so metadata, relationships, and history stay consistent.
191
+
192
+ </CRITICAL_INSTRUCTION>
193
+ <!-- BACKLOG.MD GUIDELINES END -->
@@ -0,0 +1,5 @@
1
+ # History
2
+
3
+ ## 0.1.0 (2026-08-31)
4
+
5
+ * First release on PyPI.
pstq-0.1.0/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026, Josef Nevrly
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
22
+