markback 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 (39) hide show
  1. markback-0.1.0/.gitignore +207 -0
  2. markback-0.1.0/IMPLEMENTATION_NOTES.md +119 -0
  3. markback-0.1.0/LICENSE +21 -0
  4. markback-0.1.0/PKG-INFO +251 -0
  5. markback-0.1.0/README.md +216 -0
  6. markback-0.1.0/SPEC.md +853 -0
  7. markback-0.1.0/markback/__init__.py +86 -0
  8. markback-0.1.0/markback/cli.py +435 -0
  9. markback-0.1.0/markback/config.py +181 -0
  10. markback-0.1.0/markback/linter.py +312 -0
  11. markback-0.1.0/markback/llm.py +175 -0
  12. markback-0.1.0/markback/parser.py +587 -0
  13. markback-0.1.0/markback/types.py +270 -0
  14. markback-0.1.0/markback/workflow.py +351 -0
  15. markback-0.1.0/markback/writer.py +249 -0
  16. markback-0.1.0/pyproject.toml +60 -0
  17. markback-0.1.0/tests/__init__.py +1 -0
  18. markback-0.1.0/tests/fixtures/compact_source.mb +2 -0
  19. markback-0.1.0/tests/fixtures/errors/content_with_source.mb +5 -0
  20. markback-0.1.0/tests/fixtures/errors/empty_feedback.mb +4 -0
  21. markback-0.1.0/tests/fixtures/errors/malformed_uri.mb +4 -0
  22. markback-0.1.0/tests/fixtures/errors/missing_feedback.mb +3 -0
  23. markback-0.1.0/tests/fixtures/errors/multiple_feedback.mb +5 -0
  24. markback-0.1.0/tests/fixtures/essay.label.txt +2 -0
  25. markback-0.1.0/tests/fixtures/essay.txt +4 -0
  26. markback-0.1.0/tests/fixtures/external_source.mb +3 -0
  27. markback-0.1.0/tests/fixtures/freeform_feedback.mb +16 -0
  28. markback-0.1.0/tests/fixtures/json_feedback.mb +4 -0
  29. markback-0.1.0/tests/fixtures/label_list.mb +6 -0
  30. markback-0.1.0/tests/fixtures/minimal.mb +3 -0
  31. markback-0.1.0/tests/fixtures/multi_record.mb +25 -0
  32. markback-0.1.0/tests/fixtures/with_uri.mb +4 -0
  33. markback-0.1.0/tests/test_cli.py +208 -0
  34. markback-0.1.0/tests/test_config.py +233 -0
  35. markback-0.1.0/tests/test_linter.py +228 -0
  36. markback-0.1.0/tests/test_parser.py +337 -0
  37. markback-0.1.0/tests/test_types.py +372 -0
  38. markback-0.1.0/tests/test_workflow.py +260 -0
  39. markback-0.1.0/tests/test_writer.py +289 -0
@@ -0,0 +1,207 @@
1
+ # Byte-compiled / optimized / DLL files
2
+ __pycache__/
3
+ *.py[codz]
4
+ *$py.class
5
+
6
+ # C extensions
7
+ *.so
8
+
9
+ # Distribution / packaging
10
+ .Python
11
+ build/
12
+ develop-eggs/
13
+ dist/
14
+ downloads/
15
+ eggs/
16
+ .eggs/
17
+ lib/
18
+ lib64/
19
+ parts/
20
+ sdist/
21
+ var/
22
+ wheels/
23
+ share/python-wheels/
24
+ *.egg-info/
25
+ .installed.cfg
26
+ *.egg
27
+ MANIFEST
28
+
29
+ # PyInstaller
30
+ # Usually these files are written by a python script from a template
31
+ # before PyInstaller builds the exe, so as to inject date/other infos into it.
32
+ *.manifest
33
+ *.spec
34
+
35
+ # Installer logs
36
+ pip-log.txt
37
+ pip-delete-this-directory.txt
38
+
39
+ # Unit test / coverage reports
40
+ htmlcov/
41
+ .tox/
42
+ .nox/
43
+ .coverage
44
+ .coverage.*
45
+ .cache
46
+ nosetests.xml
47
+ coverage.xml
48
+ *.cover
49
+ *.py.cover
50
+ .hypothesis/
51
+ .pytest_cache/
52
+ cover/
53
+
54
+ # Translations
55
+ *.mo
56
+ *.pot
57
+
58
+ # Django stuff:
59
+ *.log
60
+ local_settings.py
61
+ db.sqlite3
62
+ db.sqlite3-journal
63
+
64
+ # Flask stuff:
65
+ instance/
66
+ .webassets-cache
67
+
68
+ # Scrapy stuff:
69
+ .scrapy
70
+
71
+ # Sphinx documentation
72
+ docs/_build/
73
+
74
+ # PyBuilder
75
+ .pybuilder/
76
+ target/
77
+
78
+ # Jupyter Notebook
79
+ .ipynb_checkpoints
80
+
81
+ # IPython
82
+ profile_default/
83
+ ipython_config.py
84
+
85
+ # pyenv
86
+ # For a library or package, you might want to ignore these files since the code is
87
+ # intended to run in multiple environments; otherwise, check them in:
88
+ # .python-version
89
+
90
+ # pipenv
91
+ # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
92
+ # However, in case of collaboration, if having platform-specific dependencies or dependencies
93
+ # having no cross-platform support, pipenv may install dependencies that don't work, or not
94
+ # install all needed dependencies.
95
+ #Pipfile.lock
96
+
97
+ # UV
98
+ # Similar to Pipfile.lock, it is generally recommended to include uv.lock in version control.
99
+ # This is especially recommended for binary packages to ensure reproducibility, and is more
100
+ # commonly ignored for libraries.
101
+ #uv.lock
102
+
103
+ # poetry
104
+ # Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
105
+ # This is especially recommended for binary packages to ensure reproducibility, and is more
106
+ # commonly ignored for libraries.
107
+ # https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
108
+ #poetry.lock
109
+ #poetry.toml
110
+
111
+ # pdm
112
+ # Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
113
+ # pdm recommends including project-wide configuration in pdm.toml, but excluding .pdm-python.
114
+ # https://pdm-project.org/en/latest/usage/project/#working-with-version-control
115
+ #pdm.lock
116
+ #pdm.toml
117
+ .pdm-python
118
+ .pdm-build/
119
+
120
+ # pixi
121
+ # Similar to Pipfile.lock, it is generally recommended to include pixi.lock in version control.
122
+ #pixi.lock
123
+ # Pixi creates a virtual environment in the .pixi directory, just like venv module creates one
124
+ # in the .venv directory. It is recommended not to include this directory in version control.
125
+ .pixi
126
+
127
+ # PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
128
+ __pypackages__/
129
+
130
+ # Celery stuff
131
+ celerybeat-schedule
132
+ celerybeat.pid
133
+
134
+ # SageMath parsed files
135
+ *.sage.py
136
+
137
+ # Environments
138
+ .env
139
+ .envrc
140
+ .venv
141
+ env/
142
+ venv/
143
+ ENV/
144
+ env.bak/
145
+ venv.bak/
146
+
147
+ # Spyder project settings
148
+ .spyderproject
149
+ .spyproject
150
+
151
+ # Rope project settings
152
+ .ropeproject
153
+
154
+ # mkdocs documentation
155
+ /site
156
+
157
+ # mypy
158
+ .mypy_cache/
159
+ .dmypy.json
160
+ dmypy.json
161
+
162
+ # Pyre type checker
163
+ .pyre/
164
+
165
+ # pytype static type analyzer
166
+ .pytype/
167
+
168
+ # Cython debug symbols
169
+ cython_debug/
170
+
171
+ # PyCharm
172
+ # JetBrains specific template is maintained in a separate JetBrains.gitignore that can
173
+ # be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
174
+ # and can be added to the global gitignore or merged into this file. For a more nuclear
175
+ # option (not recommended) you can uncomment the following to ignore the entire idea folder.
176
+ #.idea/
177
+
178
+ # Abstra
179
+ # Abstra is an AI-powered process automation framework.
180
+ # Ignore directories containing user credentials, local state, and settings.
181
+ # Learn more at https://abstra.io/docs
182
+ .abstra/
183
+
184
+ # Visual Studio Code
185
+ # Visual Studio Code specific template is maintained in a separate VisualStudioCode.gitignore
186
+ # that can be found at https://github.com/github/gitignore/blob/main/Global/VisualStudioCode.gitignore
187
+ # and can be added to the global gitignore or merged into this file. However, if you prefer,
188
+ # you could uncomment the following to ignore the entire vscode folder
189
+ # .vscode/
190
+
191
+ # Ruff stuff:
192
+ .ruff_cache/
193
+
194
+ # PyPI configuration file
195
+ .pypirc
196
+
197
+ # Cursor
198
+ # Cursor is an AI-powered code editor. `.cursorignore` specifies files/directories to
199
+ # exclude from AI features like autocomplete and code analysis. Recommended for sensitive data
200
+ # refer to https://docs.cursor.com/context/ignore-files
201
+ .cursorignore
202
+ .cursorindexingignore
203
+
204
+ # Marimo
205
+ marimo/_static/
206
+ marimo/_lsp/
207
+ __marimo__/
@@ -0,0 +1,119 @@
1
+ # Implementation Notes
2
+
3
+ ## Design Decisions
4
+
5
+ ### Parser Architecture
6
+
7
+ The parser uses a state-machine approach, processing lines sequentially and classifying each line into one of:
8
+ - `COMPACT_RECORD` - `@source ... <<<` on one line
9
+ - `HEADER` - `@keyword value`
10
+ - `FEEDBACK` - `<<< ...`
11
+ - `SEPARATOR` - `---`
12
+ - `BLANK` - empty line
13
+ - `CONTENT` - anything else
14
+
15
+ This allows handling all format variants (single, multi, compact, paired) with the same core logic.
16
+
17
+ **Tradeoff:** The parser is single-pass but accumulates state. An alternative two-pass approach (first split on separators, then parse each segment) was considered but rejected because compact records don't require separators.
18
+
19
+ ### Feedback Parsing
20
+
21
+ Feedback parsing supports three modes:
22
+ 1. **Raw** - Return the feedback string as-is
23
+ 2. **Structured** - Parse into label, attributes, and comment
24
+ 3. **JSON** - Parse `json:{...}` prefixed feedback
25
+
26
+ The structured parser splits on `; ` (semicolon + space) and classifies segments:
27
+ - Segments with `=` are key-value attributes
28
+ - First non-attribute segment is the label
29
+ - Subsequent non-attribute segments become the comment
30
+
31
+ **Tradeoff:** This heuristic-based parsing may occasionally misclassify freeform text that happens to contain `=`. A stricter approach would require escaping, but that conflicts with the "easy to type" design goal.
32
+
33
+ ### Compact Record Detection
34
+
35
+ A line is classified as a compact record if it:
36
+ 1. Starts with `@source`
37
+ 2. Contains `<<<`
38
+
39
+ This is done before checking if it's a regular header to ensure compact records are handled correctly.
40
+
41
+ **Edge case:** A `@source` path containing `<<<` would be misinterpreted. This is documented as a limitation - paths should not contain the feedback delimiter.
42
+
43
+ ### Paired File Discovery
44
+
45
+ Paired files are discovered by:
46
+ 1. Finding all files in a directory
47
+ 2. Identifying label files by suffix (`.label.txt`, `.feedback.txt`, `.mb`)
48
+ 3. Matching content files to label files by basename
49
+
50
+ **Tradeoff:** This simple approach doesn't handle nested directories or complex naming patterns. A future version could support glob patterns or manifest files.
51
+
52
+ ### Writer Canonical Format
53
+
54
+ The writer produces deterministic output by:
55
+ 1. Normalizing line endings to LF
56
+ 2. Ordering headers (`@uri` before `@source`)
57
+ 3. Trimming trailing whitespace
58
+ 4. Using compact format for source-only records when `prefer_compact=True`
59
+
60
+ **Tradeoff:** The compact format preference is configurable because some users may prefer the more explicit full format even for simple records.
61
+
62
+ ### LLM Abstraction
63
+
64
+ The `LLMClient` abstraction supports:
65
+ - OpenAI-compatible APIs (most common)
66
+ - Mock client for testing
67
+
68
+ The factory pattern allows injecting mock clients during tests without modifying the workflow code.
69
+
70
+ **Tradeoff:** Only synchronous HTTP is supported. Async support was considered but adds complexity without clear benefit for the typical use case (small datasets, infrequent calls).
71
+
72
+ ### Evaluation Heuristics
73
+
74
+ The v1 evaluation uses simple heuristics:
75
+ - Parse the expected feedback for a label
76
+ - Check if the label is in `positive_labels` or `negative_labels`
77
+ - Look for sentiment indicators in the operator output
78
+
79
+ **Tradeoff:** This is intentionally simple and deterministic. A more sophisticated approach would use an LLM for evaluation, but that adds cost and non-determinism. The simple approach is easy to test and understand.
80
+
81
+ ### File Mode Handling
82
+
83
+ Two modes are supported:
84
+ - **git** - Modify files in place (suitable for version-controlled projects)
85
+ - **versioned** - Never overwrite, create timestamped versions
86
+
87
+ **Tradeoff:** The versioned mode uses timestamps rather than sequential numbers. This ensures uniqueness without needing to scan existing files, but timestamps can be less intuitive for ordering.
88
+
89
+ ## Known Limitations
90
+
91
+ 1. **Path restrictions:** Source paths cannot contain the `<<<` delimiter
92
+ 2. **Binary content:** Binary files are referenced but not embedded
93
+ 3. **Encoding:** Only UTF-8 is supported
94
+ 4. **Line classification:** Content cannot start with `@source ... <<<` on the first line after headers without a blank line
95
+ 5. **Evaluation:** Simple heuristic-based, not semantic understanding
96
+
97
+ ## Testing Strategy
98
+
99
+ ### Unit Tests
100
+ - Parser tests cover all format variants from the spec
101
+ - Writer tests verify roundtrip stability
102
+ - Linter tests cover all error and warning codes
103
+ - Type tests verify core data structures
104
+
105
+ ### Integration Tests
106
+ - CLI tests use Typer's test runner
107
+ - Workflow tests use mock LLM clients
108
+ - File operations use temporary directories
109
+
110
+ ### Fixtures
111
+ All spec examples are included as test fixtures to ensure the implementation matches the specification.
112
+
113
+ ## Future Considerations
114
+
115
+ 1. **Async HTTP:** Could improve throughput for large datasets
116
+ 2. **Streaming parser:** For very large files
117
+ 3. **Diff output:** Show what normalization changed
118
+ 4. **Watch mode:** Auto-lint on file changes
119
+ 5. **IDE integration:** LSP server for real-time linting
markback-0.1.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 dandriscoll
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.
@@ -0,0 +1,251 @@
1
+ Metadata-Version: 2.4
2
+ Name: markback
3
+ Version: 0.1.0
4
+ Summary: A compact, human-writable format for storing content paired with feedback/labels
5
+ Project-URL: Homepage, https://github.com/dandriscoll/markback
6
+ Project-URL: Repository, https://github.com/dandriscoll/markback
7
+ Project-URL: Documentation, https://github.com/dandriscoll/markback#readme
8
+ Project-URL: Issues, https://github.com/dandriscoll/markback/issues
9
+ Author: Dan Driscoll
10
+ License-Expression: MIT
11
+ License-File: LICENSE
12
+ Keywords: annotation,data-labeling,feedback,labeling,llm,markdown
13
+ Classifier: Development Status :: 3 - Alpha
14
+ Classifier: Environment :: Console
15
+ Classifier: Intended Audience :: Developers
16
+ Classifier: License :: OSI Approved :: MIT License
17
+ Classifier: Operating System :: OS Independent
18
+ Classifier: Programming Language :: Python :: 3
19
+ Classifier: Programming Language :: Python :: 3.10
20
+ Classifier: Programming Language :: Python :: 3.11
21
+ Classifier: Programming Language :: Python :: 3.12
22
+ Classifier: Topic :: Software Development :: Quality Assurance
23
+ Classifier: Topic :: Text Processing :: Markup
24
+ Requires-Python: >=3.10
25
+ Requires-Dist: httpx>=0.25.0
26
+ Requires-Dist: python-dotenv>=1.0.0
27
+ Requires-Dist: rich>=13.0.0
28
+ Requires-Dist: typer>=0.9.0
29
+ Provides-Extra: dev
30
+ Requires-Dist: build>=1.0.0; extra == 'dev'
31
+ Requires-Dist: pytest-cov>=4.0.0; extra == 'dev'
32
+ Requires-Dist: pytest>=7.0.0; extra == 'dev'
33
+ Requires-Dist: twine>=5.0.0; extra == 'dev'
34
+ Description-Content-Type: text/markdown
35
+
36
+ # MarkBack
37
+
38
+ A compact, human-writable format for storing content paired with feedback/labels.
39
+
40
+ ## Installation
41
+
42
+ ```bash
43
+ pip install -e .
44
+ ```
45
+
46
+ ## Quick Start
47
+
48
+ ### Parse a MarkBack file
49
+
50
+ ```python
51
+ from markback import parse_file, parse_string
52
+
53
+ # Parse a file
54
+ result = parse_file("labels.mb")
55
+ for record in result.records:
56
+ print(f"{record.uri}: {record.feedback}")
57
+
58
+ # Parse a string
59
+ text = """
60
+ @uri local:example
61
+
62
+ Some content here.
63
+ <<< positive; good quality
64
+ """
65
+ result = parse_string(text)
66
+ ```
67
+
68
+ ### Write MarkBack files
69
+
70
+ ```python
71
+ from markback import Record, SourceRef, write_file, OutputMode
72
+
73
+ records = [
74
+ Record(feedback="good", uri="local:1", content="First item"),
75
+ Record(feedback="bad", uri="local:2", content="Second item"),
76
+ ]
77
+
78
+ # Write multi-record file
79
+ write_file("output.mb", records, mode=OutputMode.MULTI)
80
+
81
+ # Write compact label list
82
+ write_file("labels.mb", records, mode=OutputMode.COMPACT)
83
+ ```
84
+
85
+ ### Lint files
86
+
87
+ ```python
88
+ from markback import lint_file
89
+
90
+ result = lint_file("myfile.mb")
91
+ if result.has_errors:
92
+ for d in result.diagnostics:
93
+ print(d)
94
+ ```
95
+
96
+ ## CLI Usage
97
+
98
+ ### Initialize configuration
99
+
100
+ ```bash
101
+ markback init
102
+ ```
103
+
104
+ Creates a `.env` file with all configuration options.
105
+
106
+ ### Lint files
107
+
108
+ ```bash
109
+ # Lint a single file
110
+ markback lint myfile.mb
111
+
112
+ # Lint a directory
113
+ markback lint ./data/
114
+
115
+ # JSON output
116
+ markback lint myfile.mb --json
117
+ ```
118
+
119
+ ### Normalize to canonical format
120
+
121
+ ```bash
122
+ # Output to stdout
123
+ markback normalize input.mb
124
+
125
+ # Output to file
126
+ markback normalize input.mb output.mb
127
+
128
+ # In-place normalization
129
+ markback normalize input.mb --in-place
130
+ ```
131
+
132
+ ### List records
133
+
134
+ ```bash
135
+ markback list myfile.mb
136
+ markback list ./data/ --json
137
+ ```
138
+
139
+ ### Convert between formats
140
+
141
+ ```bash
142
+ # Convert to multi-record format
143
+ markback convert input.mb output.mb --to multi
144
+
145
+ # Convert to compact label list
146
+ markback convert input.mb output.mb --to compact
147
+
148
+ # Convert to paired files
149
+ markback convert input.mb ./output_dir/ --to paired
150
+ ```
151
+
152
+ ### Run LLM workflow
153
+
154
+ ```bash
155
+ # Run editor/operator workflow
156
+ markback workflow run dataset.mb --prompt "Initial prompt" --output results.json
157
+
158
+ # View evaluation results
159
+ markback workflow evaluate results.json
160
+
161
+ # Extract refined prompt
162
+ markback workflow prompt results.json --output refined_prompt.txt
163
+ ```
164
+
165
+ ## File Formats
166
+
167
+ ### Single Record
168
+
169
+ ```
170
+ @uri local:example
171
+
172
+ Content goes here.
173
+ <<< positive; quality=high
174
+ ```
175
+
176
+ ### Multi-Record
177
+
178
+ ```
179
+ @uri local:item-1
180
+
181
+ First content.
182
+ <<< good
183
+
184
+ ---
185
+ @uri local:item-2
186
+
187
+ Second content.
188
+ <<< bad; needs improvement
189
+ ```
190
+
191
+ ### Compact Label List
192
+
193
+ ```
194
+ @source ./images/001.jpg <<< approved; scene=beach
195
+ @source ./images/002.jpg <<< rejected; too dark
196
+ @source ./images/003.jpg <<< approved; scene=mountain
197
+ ```
198
+
199
+ ### Paired Files
200
+
201
+ **content.txt:**
202
+ ```
203
+ The actual content goes here.
204
+ ```
205
+
206
+ **content.label.txt:**
207
+ ```
208
+ @uri local:content-id
209
+ <<< approved; reviewer=alice
210
+ ```
211
+
212
+ ## Configuration
213
+
214
+ Configuration is loaded from `.env`:
215
+
216
+ ```bash
217
+ # File handling mode
218
+ FILE_MODE=git # or "versioned"
219
+
220
+ # Label file discovery
221
+ LABEL_SUFFIXES=.label.txt,.feedback.txt,.mb
222
+
223
+ # Editor LLM
224
+ EDITOR_API_BASE=https://api.openai.com/v1
225
+ EDITOR_API_KEY=your-key
226
+ EDITOR_MODEL=gpt-4
227
+
228
+ # Operator LLM
229
+ OPERATOR_API_BASE=https://api.openai.com/v1
230
+ OPERATOR_API_KEY=your-key
231
+ OPERATOR_MODEL=gpt-4
232
+ ```
233
+
234
+ ## Development
235
+
236
+ ### Run tests
237
+
238
+ ```bash
239
+ pip install -e ".[dev]"
240
+ pytest
241
+ ```
242
+
243
+ ### Run with coverage
244
+
245
+ ```bash
246
+ pytest --cov=markback
247
+ ```
248
+
249
+ ## License
250
+
251
+ MIT