articulate-writing 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.
- articulate_writing-0.1.0/.gitattributes +7 -0
- articulate_writing-0.1.0/.github/workflows/ci.yml +48 -0
- articulate_writing-0.1.0/.github/workflows/publish.yml +41 -0
- articulate_writing-0.1.0/.gitignore +34 -0
- articulate_writing-0.1.0/.pre-commit-hooks.yaml +7 -0
- articulate_writing-0.1.0/LICENSE +110 -0
- articulate_writing-0.1.0/PKG-INFO +161 -0
- articulate_writing-0.1.0/README.md +138 -0
- articulate_writing-0.1.0/action.yml +48 -0
- articulate_writing-0.1.0/corpus/ai/blog-intro.md +1 -0
- articulate_writing-0.1.0/corpus/ai/email-outreach.md +1 -0
- articulate_writing-0.1.0/corpus/ai/flagship-clean.pangram +1 -0
- articulate_writing-0.1.0/corpus/ai/flagship-clean.txt +111 -0
- articulate_writing-0.1.0/corpus/ai/medium.md +1 -0
- articulate_writing-0.1.0/corpus/ai/slop-heavy.md +1 -0
- articulate_writing-0.1.0/corpus/human/declaration-preamble.txt +1 -0
- articulate_writing-0.1.0/corpus/human/gettysburg.txt +1 -0
- articulate_writing-0.1.0/corpus/human/lincoln-2nd-inaugural.txt +1 -0
- articulate_writing-0.1.0/corpus/human/ptacek-tweets.pangram +1 -0
- articulate_writing-0.1.0/corpus/human/ptacek-tweets.txt +1 -0
- articulate_writing-0.1.0/docs/README.md +28 -0
- articulate_writing-0.1.0/docs/boundaries.md +71 -0
- articulate_writing-0.1.0/docs/cli.md +104 -0
- articulate_writing-0.1.0/docs/features.md +172 -0
- articulate_writing-0.1.0/docs/getting-started.md +112 -0
- articulate_writing-0.1.0/docs/walkthrough.md +165 -0
- articulate_writing-0.1.0/editors/jetbrains/README.md +36 -0
- articulate_writing-0.1.0/editors/vscode/.vscodeignore +7 -0
- articulate_writing-0.1.0/editors/vscode/README.md +32 -0
- articulate_writing-0.1.0/editors/vscode/package-lock.json +140 -0
- articulate_writing-0.1.0/editors/vscode/package.json +53 -0
- articulate_writing-0.1.0/editors/vscode/src/extension.ts +76 -0
- articulate_writing-0.1.0/editors/vscode/tsconfig.json +15 -0
- articulate_writing-0.1.0/pyproject.toml +38 -0
- articulate_writing-0.1.0/src/articulate/__init__.py +13 -0
- articulate_writing-0.1.0/src/articulate/bench.py +143 -0
- articulate_writing-0.1.0/src/articulate/cli.py +459 -0
- articulate_writing-0.1.0/src/articulate/detector.py +1236 -0
- articulate_writing-0.1.0/src/articulate/editor.py +563 -0
- articulate_writing-0.1.0/src/articulate/genres.py +129 -0
- articulate_writing-0.1.0/src/articulate/lsp_server.py +143 -0
- articulate_writing-0.1.0/src/articulate/mcp_server.py +195 -0
- articulate_writing-0.1.0/src/articulate/modes.py +238 -0
- articulate_writing-0.1.0/src/articulate/profiles.py +175 -0
- articulate_writing-0.1.0/src/articulate/py.typed +0 -0
- articulate_writing-0.1.0/src/articulate/pysource.py +74 -0
- articulate_writing-0.1.0/src/articulate/receipt.py +193 -0
- articulate_writing-0.1.0/tests/conftest.py +5 -0
- articulate_writing-0.1.0/tests/test_audit.py +110 -0
- articulate_writing-0.1.0/tests/test_audit_cli.py +137 -0
- articulate_writing-0.1.0/tests/test_audit_hardening.py +124 -0
- articulate_writing-0.1.0/tests/test_binary_guard.py +71 -0
- articulate_writing-0.1.0/tests/test_detector.py +99 -0
- articulate_writing-0.1.0/tests/test_dogfood.py +41 -0
- articulate_writing-0.1.0/tests/test_editor.py +78 -0
- articulate_writing-0.1.0/tests/test_genres.py +148 -0
- articulate_writing-0.1.0/tests/test_injection.py +73 -0
- articulate_writing-0.1.0/tests/test_lsp.py +74 -0
- articulate_writing-0.1.0/tests/test_modes.py +53 -0
- articulate_writing-0.1.0/tests/test_receipt.py +66 -0
- articulate_writing-0.1.0/tests/test_redos.py +78 -0
- articulate_writing-0.1.0/tests/test_science.py +137 -0
- articulate_writing-0.1.0/tests/test_spans.py +85 -0
- articulate_writing-0.1.0/tests/test_thresholds.py +66 -0
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
# Normalize line endings to LF in the repository, so a CRLF/LF checkout never
|
|
2
|
+
# rewrites a file and never reads as a spurious change (the receipt text hash is
|
|
3
|
+
# byte-exact). Matches the CLI's own line-ending canonicalization.
|
|
4
|
+
* text=auto eol=lf
|
|
5
|
+
*.png binary
|
|
6
|
+
*.jpg binary
|
|
7
|
+
*.gif binary
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
pull_request:
|
|
7
|
+
|
|
8
|
+
jobs:
|
|
9
|
+
test:
|
|
10
|
+
runs-on: ubuntu-latest
|
|
11
|
+
strategy:
|
|
12
|
+
matrix:
|
|
13
|
+
python: ["3.9", "3.10", "3.11", "3.12"]
|
|
14
|
+
steps:
|
|
15
|
+
- uses: actions/checkout@v4
|
|
16
|
+
- uses: actions/setup-python@v5
|
|
17
|
+
with:
|
|
18
|
+
python-version: ${{ matrix.python }}
|
|
19
|
+
- run: pip install -e ".[dev]"
|
|
20
|
+
# The suite gates on the benchmark (recall/specificity), the dogfood check
|
|
21
|
+
# (our own prose passes our own standard), the mode/receipt/LSP contracts,
|
|
22
|
+
# and the ReDoS safety test.
|
|
23
|
+
- run: python -m pytest -q
|
|
24
|
+
|
|
25
|
+
articulate-self-check:
|
|
26
|
+
runs-on: ubuntu-latest
|
|
27
|
+
steps:
|
|
28
|
+
- uses: actions/checkout@v4
|
|
29
|
+
- uses: actions/setup-python@v5
|
|
30
|
+
with:
|
|
31
|
+
python-version: "3.12"
|
|
32
|
+
- run: pip install -e .
|
|
33
|
+
# Dogfood in CI: our shipped docs must pass our own gate.
|
|
34
|
+
- run: python -m articulate.cli check README.md docs/*.md --gate
|
|
35
|
+
|
|
36
|
+
build:
|
|
37
|
+
runs-on: ubuntu-latest
|
|
38
|
+
steps:
|
|
39
|
+
- uses: actions/checkout@v4
|
|
40
|
+
- uses: actions/setup-python@v5
|
|
41
|
+
with:
|
|
42
|
+
python-version: "3.12"
|
|
43
|
+
- run: pip install build
|
|
44
|
+
- run: python -m build
|
|
45
|
+
- uses: actions/upload-artifact@v4
|
|
46
|
+
with:
|
|
47
|
+
name: dist
|
|
48
|
+
path: dist/*
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
name: Publish to PyPI
|
|
2
|
+
|
|
3
|
+
# Publishes the package when a GitHub Release is published, or on a manual run.
|
|
4
|
+
# Uses PyPI Trusted Publishing (OIDC): no API token is stored in the repository.
|
|
5
|
+
# One-time setup on PyPI: add a pending publisher for project "articulate-writing"
|
|
6
|
+
# pointing at this repository, the workflow file "publish.yml", and the environment
|
|
7
|
+
# "pypi". See https://docs.pypi.org/trusted-publishers/.
|
|
8
|
+
|
|
9
|
+
on:
|
|
10
|
+
release:
|
|
11
|
+
types: [published]
|
|
12
|
+
workflow_dispatch:
|
|
13
|
+
|
|
14
|
+
jobs:
|
|
15
|
+
build:
|
|
16
|
+
runs-on: ubuntu-latest
|
|
17
|
+
steps:
|
|
18
|
+
- uses: actions/checkout@v4
|
|
19
|
+
- uses: actions/setup-python@v5
|
|
20
|
+
with:
|
|
21
|
+
python-version: "3.12"
|
|
22
|
+
- run: pip install build twine
|
|
23
|
+
- run: python -m build
|
|
24
|
+
- run: python -m twine check dist/*
|
|
25
|
+
- uses: actions/upload-artifact@v4
|
|
26
|
+
with:
|
|
27
|
+
name: dist
|
|
28
|
+
path: dist/
|
|
29
|
+
|
|
30
|
+
publish:
|
|
31
|
+
needs: build
|
|
32
|
+
runs-on: ubuntu-latest
|
|
33
|
+
environment: pypi
|
|
34
|
+
permissions:
|
|
35
|
+
id-token: write # required for OIDC Trusted Publishing
|
|
36
|
+
steps:
|
|
37
|
+
- uses: actions/download-artifact@v4
|
|
38
|
+
with:
|
|
39
|
+
name: dist
|
|
40
|
+
path: dist/
|
|
41
|
+
- uses: pypa/gh-action-pypi-publish@release/v1
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# Secrets / env (standard workspace rule; the negation must follow .env.*)
|
|
2
|
+
.env
|
|
3
|
+
.env.*
|
|
4
|
+
!.env.example
|
|
5
|
+
.envrc
|
|
6
|
+
.envrc.local
|
|
7
|
+
CLAUDE.local.md
|
|
8
|
+
|
|
9
|
+
# Python
|
|
10
|
+
__pycache__/
|
|
11
|
+
*.py[cod]
|
|
12
|
+
*.egg-info/
|
|
13
|
+
.eggs/
|
|
14
|
+
build/
|
|
15
|
+
dist/
|
|
16
|
+
.pytest_cache/
|
|
17
|
+
.mypy_cache/
|
|
18
|
+
.ruff_cache/
|
|
19
|
+
.venv/
|
|
20
|
+
venv/
|
|
21
|
+
|
|
22
|
+
# Editor extension deps and build output (package.json/-lock.json stay tracked)
|
|
23
|
+
node_modules/
|
|
24
|
+
out/
|
|
25
|
+
*.vsix
|
|
26
|
+
|
|
27
|
+
# OS
|
|
28
|
+
.DS_Store
|
|
29
|
+
Thumbs.db
|
|
30
|
+
|
|
31
|
+
# Internal-only: strategy/scope with local paths and pricing, and the migration
|
|
32
|
+
# checklist that references local tooling. Kept out of the public repo.
|
|
33
|
+
project-docs/
|
|
34
|
+
MIGRATION.md
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
# Functional Source License, Version 1.1, MIT Future License
|
|
2
|
+
|
|
3
|
+
## Abbreviation
|
|
4
|
+
|
|
5
|
+
FSL-1.1-MIT
|
|
6
|
+
|
|
7
|
+
## Notice
|
|
8
|
+
|
|
9
|
+
Copyright 2026 Zain Dana Harper
|
|
10
|
+
|
|
11
|
+
## Terms and Conditions
|
|
12
|
+
|
|
13
|
+
### Licensor ("We")
|
|
14
|
+
|
|
15
|
+
The party offering the Software under these Terms and Conditions.
|
|
16
|
+
|
|
17
|
+
### The Software
|
|
18
|
+
|
|
19
|
+
The "Software" is each version of the software that we make available under
|
|
20
|
+
these Terms and Conditions, as indicated by our inclusion of these Terms and
|
|
21
|
+
Conditions with the Software.
|
|
22
|
+
|
|
23
|
+
### License Grant
|
|
24
|
+
|
|
25
|
+
Subject to your compliance with this License Grant and the Patents,
|
|
26
|
+
Redistribution and Trademark clauses below, we hereby grant you the right to
|
|
27
|
+
use, copy, modify, create derivative works, publicly perform, publicly display
|
|
28
|
+
and redistribute the Software for any Permitted Purpose identified below.
|
|
29
|
+
|
|
30
|
+
### Permitted Purpose
|
|
31
|
+
|
|
32
|
+
A Permitted Purpose is any purpose other than a Competing Use. A Competing Use
|
|
33
|
+
means making the Software available to others in a commercial product or
|
|
34
|
+
service that:
|
|
35
|
+
|
|
36
|
+
1. substitutes for the Software;
|
|
37
|
+
|
|
38
|
+
2. substitutes for any other product or service we offer using the Software
|
|
39
|
+
that exists as of the date we make the Software available; or
|
|
40
|
+
|
|
41
|
+
3. offers the same or substantially similar functionality as the Software.
|
|
42
|
+
|
|
43
|
+
Permitted Purposes specifically include using the Software:
|
|
44
|
+
|
|
45
|
+
1. for your internal use and access;
|
|
46
|
+
|
|
47
|
+
2. for non-commercial education;
|
|
48
|
+
|
|
49
|
+
3. for non-commercial research; and
|
|
50
|
+
|
|
51
|
+
4. in connection with professional services that you provide to a licensee
|
|
52
|
+
using the Software in accordance with these Terms and Conditions.
|
|
53
|
+
|
|
54
|
+
### Patents
|
|
55
|
+
|
|
56
|
+
To the extent your use for a Permitted Purpose would necessarily infringe our
|
|
57
|
+
patents, the license grant above includes a license under our patents. If you
|
|
58
|
+
make a claim against any party that the Software infringes or contributes to
|
|
59
|
+
the infringement of any patent, then your patent license to the Software ends
|
|
60
|
+
immediately.
|
|
61
|
+
|
|
62
|
+
### Redistribution
|
|
63
|
+
|
|
64
|
+
The Terms and Conditions apply to all copies, modifications and derivatives of
|
|
65
|
+
the Software.
|
|
66
|
+
|
|
67
|
+
If you redistribute any copies, modifications or derivatives of the Software,
|
|
68
|
+
you must include a copy of or a link to these Terms and Conditions and not
|
|
69
|
+
remove any copyright notices provided in or with the Software.
|
|
70
|
+
|
|
71
|
+
### Disclaimer
|
|
72
|
+
|
|
73
|
+
THE SOFTWARE IS PROVIDED "AS IS" AND WITHOUT WARRANTIES OF ANY KIND, EXPRESS OR
|
|
74
|
+
IMPLIED, INCLUDING WITHOUT LIMITATION WARRANTIES OF FITNESS FOR A PARTICULAR
|
|
75
|
+
PURPOSE, MERCHANTABILITY, TITLE OR NON-INFRINGEMENT.
|
|
76
|
+
|
|
77
|
+
IN NO EVENT WILL WE HAVE ANY LIABILITY TO YOU ARISING OUT OF OR RELATED TO THE
|
|
78
|
+
SOFTWARE, INCLUDING INDIRECT, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES,
|
|
79
|
+
EVEN IF WE HAVE BEEN INFORMED OF THEIR POSSIBILITY IN ADVANCE.
|
|
80
|
+
|
|
81
|
+
### Trademarks
|
|
82
|
+
|
|
83
|
+
Except for displaying the License Details and identifying us as the origin of
|
|
84
|
+
the Software, you have no right under these Terms and Conditions to use our
|
|
85
|
+
trademarks, trade names, service marks or product names.
|
|
86
|
+
|
|
87
|
+
## Grant of Future License
|
|
88
|
+
|
|
89
|
+
We hereby irrevocably grant you an additional license to use the Software under
|
|
90
|
+
the MIT license that is effective on the second anniversary of the date we make
|
|
91
|
+
the Software available. On or after that date, you may use the Software under
|
|
92
|
+
the MIT license, in which case the following will apply:
|
|
93
|
+
|
|
94
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
|
95
|
+
this software and associated documentation files (the "Software"), to deal in
|
|
96
|
+
the Software without restriction, including without limitation the rights to
|
|
97
|
+
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
|
98
|
+
of the Software, and to permit persons to whom the Software is furnished to do
|
|
99
|
+
so, subject to the following conditions:
|
|
100
|
+
|
|
101
|
+
The above copyright notice and this permission notice shall be included in all
|
|
102
|
+
copies or substantial portions of the Software.
|
|
103
|
+
|
|
104
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
105
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
106
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
107
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
108
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
109
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
110
|
+
SOFTWARE.
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: articulate-writing
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Local, re-derivable writing-quality and AI-tell detection and editing: register profiles, writing modes, a genre axis, and content-free audit receipts.
|
|
5
|
+
Project-URL: Homepage, https://github.com/HarperZ9/articulate
|
|
6
|
+
Project-URL: Repository, https://github.com/HarperZ9/articulate
|
|
7
|
+
Project-URL: Documentation, https://github.com/HarperZ9/articulate/tree/main/docs
|
|
8
|
+
Project-URL: Issues, https://github.com/HarperZ9/articulate/issues
|
|
9
|
+
Author: Zain Dana Harper
|
|
10
|
+
License-Expression: LicenseRef-FSL-1.1-MIT
|
|
11
|
+
License-File: LICENSE
|
|
12
|
+
Keywords: ai-detection,audit,editor,linter,prose,quality,receipt,writing
|
|
13
|
+
Classifier: Environment :: Console
|
|
14
|
+
Classifier: Intended Audience :: Developers
|
|
15
|
+
Classifier: Programming Language :: Python :: 3
|
|
16
|
+
Classifier: Topic :: Text Processing :: Linguistic
|
|
17
|
+
Requires-Python: >=3.9
|
|
18
|
+
Provides-Extra: dev
|
|
19
|
+
Requires-Dist: pytest>=7; extra == 'dev'
|
|
20
|
+
Provides-Extra: mcp
|
|
21
|
+
Requires-Dist: fastmcp>=3; extra == 'mcp'
|
|
22
|
+
Description-Content-Type: text/markdown
|
|
23
|
+
|
|
24
|
+
# Articulate
|
|
25
|
+
|
|
26
|
+
A local writing-quality and AI-tell detection and editing tool. It flags the
|
|
27
|
+
prose devices and machine-writing tells that make text read as generated, scores
|
|
28
|
+
how machine-textured a passage is, and (with an LLM backend) rewrites prose to a
|
|
29
|
+
plain, skilled standard. The core runs standard-library-only with no network
|
|
30
|
+
call. Detection quality and writing quality are the goals; a detector score is a
|
|
31
|
+
benchmark and a byproduct, never something the tool optimizes toward, and it is
|
|
32
|
+
not an evasion tool.
|
|
33
|
+
|
|
34
|
+
## Documentation
|
|
35
|
+
|
|
36
|
+
Full docs are in [`docs/`](docs/): [getting started](docs/getting-started.md), a
|
|
37
|
+
thorough [walkthrough](docs/walkthrough.md), the [feature reference](docs/features.md),
|
|
38
|
+
the [CLI reference](docs/cli.md), and the [boundaries](docs/boundaries.md) that
|
|
39
|
+
say what a verdict and a receipt mean and what they never claim.
|
|
40
|
+
|
|
41
|
+
## What it does
|
|
42
|
+
|
|
43
|
+
- **Detect.** Flags banned rhetorical devices (antithesis including keyword-free
|
|
44
|
+
parallel-negation contrast pairs, corrective negation, rule-of-three, em-dashes,
|
|
45
|
+
filler intensifiers, corporate verbs), current frontier-model register,
|
|
46
|
+
marketing, and email/blog tells, and Williams/Orwell signals (expletive openers,
|
|
47
|
+
nominalization density, passive voice, adverb density, cadence uniformity,
|
|
48
|
+
opener repetition). Emits a graded 0-100 texture score and a clean/flagged gate.
|
|
49
|
+
- **Adapt by register.** A profile system (procedure, commit, research, readme,
|
|
50
|
+
essay, narrative, and more) sets which findings block. Fiction gates nothing;
|
|
51
|
+
procedures and essays gate strictly. Profiles resolve from `--profile`, an
|
|
52
|
+
in-file `writing-profile:` tag, or the file path.
|
|
53
|
+
- **Choose a mode or a genre.** A writing mode crosses a domain register with an
|
|
54
|
+
articulation need, such as `memo/argue` or `technical-docs/explain`. The genre
|
|
55
|
+
axis reads narrative and expressive prose by its own convention: `literary-fiction`,
|
|
56
|
+
`genre-fiction`, `ya-fiction`, `memoir`, `screenplay`, `poetry`. Under a fiction
|
|
57
|
+
genre, quoted speech is masked out of the device passes so a character's line is
|
|
58
|
+
never scored as the author's prose; the craft devices report but never block; and
|
|
59
|
+
a report-only lexicon flags generation artifacts such as the somatic cliche or the
|
|
60
|
+
"could not help but" reflexive. Screenplay classifies Fountain roles first, so only
|
|
61
|
+
action lines face the device gate. Poetry reads by the line and drops the
|
|
62
|
+
craft-device categories from its report. Run `articulate modes` to list them.
|
|
63
|
+
- **Edit.** `judge` reads the judgment-level failures a regex cannot see
|
|
64
|
+
(confident emptiness, vague abstraction, hedging with no position, weak verbs).
|
|
65
|
+
`fix` rewrites to the standard, self-checked against the detector. `polish`
|
|
66
|
+
loops until five qualities (concreteness, commitment, economy, rhythm, a
|
|
67
|
+
restatable fact per paragraph) clear a bar. Gated on writing quality, never a
|
|
68
|
+
detector score. Needs an LLM backend (local model or the `claude` CLI).
|
|
69
|
+
|
|
70
|
+
## Use
|
|
71
|
+
|
|
72
|
+
```bash
|
|
73
|
+
# lint (exit 1 when blocked under the file's profile)
|
|
74
|
+
python -m articulate.cli check path/to/doc.md --gate
|
|
75
|
+
python -m articulate.cli check essay.md --profile essay --verbose
|
|
76
|
+
echo "some prose" | python -m articulate.cli score
|
|
77
|
+
|
|
78
|
+
# library
|
|
79
|
+
python -c "import articulate; print(articulate.check_text('...', profile=articulate.profiles.load('research'))['gate'])"
|
|
80
|
+
|
|
81
|
+
# receipt: a re-derivable verdict (Match / Drift / Unverifiable)
|
|
82
|
+
python -m articulate.cli receipt doc.md --profile research > doc.receipt.json
|
|
83
|
+
python -m articulate.cli verify doc.receipt.json doc.md # replay; exit 0/1/2
|
|
84
|
+
|
|
85
|
+
# content-free audit receipt: replayable, but stores no verbatim text (drop or hash
|
|
86
|
+
# the matched substring). For a team that must retain a record without the source.
|
|
87
|
+
python -m articulate.cli receipt doc.md --redact drop --reviewer alice > receipts/doc.json
|
|
88
|
+
python -m articulate.cli check doc.md --content-free --sarif > doc.sarif # no substrings
|
|
89
|
+
|
|
90
|
+
# audit: query committed receipts locally (no server), and re-verify they still hold
|
|
91
|
+
python -m articulate.cli audit receipts/ # recorded verdicts, blocked rules
|
|
92
|
+
python -m articulate.cli audit receipts/ --reverify --gate # exit 1 if a source drifted
|
|
93
|
+
|
|
94
|
+
# SARIF for CI (GitHub Code Scanning, Azure, reviewdog)
|
|
95
|
+
python -m articulate.cli check src/**/*.md --sarif > articulate.sarif
|
|
96
|
+
|
|
97
|
+
# LSP server (inline squiggles in VS Code, JetBrains via LSP4IJ, Neovim). Stdlib
|
|
98
|
+
# only, no dependency. Point your editor's LSP client at:
|
|
99
|
+
python -m articulate.lsp_server
|
|
100
|
+
|
|
101
|
+
# benchmark (regression-gated corpus) and MCP server
|
|
102
|
+
python -m articulate.bench
|
|
103
|
+
python -m articulate.mcp_server
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
### Editor setup
|
|
107
|
+
|
|
108
|
+
The LSP server speaks standard LSP over stdio, so any LSP client can drive it.
|
|
109
|
+
A minimal Neovim registration:
|
|
110
|
+
|
|
111
|
+
```lua
|
|
112
|
+
vim.lsp.start({ name = "articulate", cmd = { "python", "-m", "articulate.lsp_server" },
|
|
113
|
+
filetypes = { "markdown", "text", "tex" } })
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
For VS Code, a thin client that launches the same command as a `LanguageClient`
|
|
117
|
+
is all that is needed; no server code lives in the extension.
|
|
118
|
+
|
|
119
|
+
### Scientific and mathematical writing
|
|
120
|
+
|
|
121
|
+
`academic/prove` and `science-writing/explain` target hard technical exposition:
|
|
122
|
+
stating the idea before the formalism, keeping a roadmap, defining each symbol
|
|
123
|
+
once. The proof mode does not rewrite by default, because a wrong change to a
|
|
124
|
+
quantifier order or an inequality direction changes a theorem; it routes to
|
|
125
|
+
`--judge`, and `--fix` is opt-in. On a `.tex` file the editor masks every math
|
|
126
|
+
span before a rewrite and splices it back byte for byte, so a formula is never
|
|
127
|
+
altered.
|
|
128
|
+
|
|
129
|
+
The boundary is fixed and load-bearing: a clean gate, a low texture score, or a
|
|
130
|
+
Match receipt means the prose was screened under a named ruleset. It says nothing
|
|
131
|
+
about whether the theorem is true. A clearly written proof can still be false, and
|
|
132
|
+
Articulate never checks the mathematics. Correctness comes from referees and proof
|
|
133
|
+
assistants (Lean, Coq, Isabelle), never from this tool.
|
|
134
|
+
|
|
135
|
+
## Privacy
|
|
136
|
+
|
|
137
|
+
The detector never touches the network. The editor layer defaults to a local
|
|
138
|
+
model where configured, and an `--offline` mode is on the roadmap for air-gapped
|
|
139
|
+
use. A content-free audit receipt keeps no verbatim text: it drops the matched
|
|
140
|
+
substring and the exact offsets, keeping only which rule fired, its tier and
|
|
141
|
+
category, and the line. A team can retain and replay a record without storing the
|
|
142
|
+
sensitive source. Content-free is not zero-leakage: which rules fired and the line
|
|
143
|
+
remain, which for a closed-vocabulary rule narrows the flagged word to that rule's
|
|
144
|
+
small public candidate set. The `hash` mode keeps a sha256 for an equality check
|
|
145
|
+
against a known string, so it is dictionary-reversible for those closed-vocabulary
|
|
146
|
+
rules; use `drop` when the flagged word must stay secret. An auto-filled `reviewer`
|
|
147
|
+
(from `$GITHUB_ACTOR`) records CI attribution, and a named human sign-off needs an
|
|
148
|
+
explicit `--reviewer`. Committed receipts live as long as the repo, with no
|
|
149
|
+
automatic expiry (bounded retention is a later self-hosted tier). The full
|
|
150
|
+
[documentation](docs/) covers each surface and the boundaries in depth.
|
|
151
|
+
|
|
152
|
+
## Status
|
|
153
|
+
|
|
154
|
+
Pre-1.0. The core detector, profile system, writing modes (including the science
|
|
155
|
+
modes for proofs and technical exposition), the genre axis (fiction, memoir,
|
|
156
|
+
screenplay, poetry), the editor injection boundary, per-span mixed-authorship
|
|
157
|
+
verdicts, a sub-threshold "unverifiable" calibration, binary fail-closed input
|
|
158
|
+
guards, the benchmark, the editor layer, the CLI, the LSP and SARIF surfaces,
|
|
159
|
+
receipts, the content-free audit receipt, and the MCP server are built into this
|
|
160
|
+
one package. A local-model editor backend, a labeled non-native corpus for a
|
|
161
|
+
fairness check, and PyPI packaging are on the roadmap.
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
# Articulate
|
|
2
|
+
|
|
3
|
+
A local writing-quality and AI-tell detection and editing tool. It flags the
|
|
4
|
+
prose devices and machine-writing tells that make text read as generated, scores
|
|
5
|
+
how machine-textured a passage is, and (with an LLM backend) rewrites prose to a
|
|
6
|
+
plain, skilled standard. The core runs standard-library-only with no network
|
|
7
|
+
call. Detection quality and writing quality are the goals; a detector score is a
|
|
8
|
+
benchmark and a byproduct, never something the tool optimizes toward, and it is
|
|
9
|
+
not an evasion tool.
|
|
10
|
+
|
|
11
|
+
## Documentation
|
|
12
|
+
|
|
13
|
+
Full docs are in [`docs/`](docs/): [getting started](docs/getting-started.md), a
|
|
14
|
+
thorough [walkthrough](docs/walkthrough.md), the [feature reference](docs/features.md),
|
|
15
|
+
the [CLI reference](docs/cli.md), and the [boundaries](docs/boundaries.md) that
|
|
16
|
+
say what a verdict and a receipt mean and what they never claim.
|
|
17
|
+
|
|
18
|
+
## What it does
|
|
19
|
+
|
|
20
|
+
- **Detect.** Flags banned rhetorical devices (antithesis including keyword-free
|
|
21
|
+
parallel-negation contrast pairs, corrective negation, rule-of-three, em-dashes,
|
|
22
|
+
filler intensifiers, corporate verbs), current frontier-model register,
|
|
23
|
+
marketing, and email/blog tells, and Williams/Orwell signals (expletive openers,
|
|
24
|
+
nominalization density, passive voice, adverb density, cadence uniformity,
|
|
25
|
+
opener repetition). Emits a graded 0-100 texture score and a clean/flagged gate.
|
|
26
|
+
- **Adapt by register.** A profile system (procedure, commit, research, readme,
|
|
27
|
+
essay, narrative, and more) sets which findings block. Fiction gates nothing;
|
|
28
|
+
procedures and essays gate strictly. Profiles resolve from `--profile`, an
|
|
29
|
+
in-file `writing-profile:` tag, or the file path.
|
|
30
|
+
- **Choose a mode or a genre.** A writing mode crosses a domain register with an
|
|
31
|
+
articulation need, such as `memo/argue` or `technical-docs/explain`. The genre
|
|
32
|
+
axis reads narrative and expressive prose by its own convention: `literary-fiction`,
|
|
33
|
+
`genre-fiction`, `ya-fiction`, `memoir`, `screenplay`, `poetry`. Under a fiction
|
|
34
|
+
genre, quoted speech is masked out of the device passes so a character's line is
|
|
35
|
+
never scored as the author's prose; the craft devices report but never block; and
|
|
36
|
+
a report-only lexicon flags generation artifacts such as the somatic cliche or the
|
|
37
|
+
"could not help but" reflexive. Screenplay classifies Fountain roles first, so only
|
|
38
|
+
action lines face the device gate. Poetry reads by the line and drops the
|
|
39
|
+
craft-device categories from its report. Run `articulate modes` to list them.
|
|
40
|
+
- **Edit.** `judge` reads the judgment-level failures a regex cannot see
|
|
41
|
+
(confident emptiness, vague abstraction, hedging with no position, weak verbs).
|
|
42
|
+
`fix` rewrites to the standard, self-checked against the detector. `polish`
|
|
43
|
+
loops until five qualities (concreteness, commitment, economy, rhythm, a
|
|
44
|
+
restatable fact per paragraph) clear a bar. Gated on writing quality, never a
|
|
45
|
+
detector score. Needs an LLM backend (local model or the `claude` CLI).
|
|
46
|
+
|
|
47
|
+
## Use
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
# lint (exit 1 when blocked under the file's profile)
|
|
51
|
+
python -m articulate.cli check path/to/doc.md --gate
|
|
52
|
+
python -m articulate.cli check essay.md --profile essay --verbose
|
|
53
|
+
echo "some prose" | python -m articulate.cli score
|
|
54
|
+
|
|
55
|
+
# library
|
|
56
|
+
python -c "import articulate; print(articulate.check_text('...', profile=articulate.profiles.load('research'))['gate'])"
|
|
57
|
+
|
|
58
|
+
# receipt: a re-derivable verdict (Match / Drift / Unverifiable)
|
|
59
|
+
python -m articulate.cli receipt doc.md --profile research > doc.receipt.json
|
|
60
|
+
python -m articulate.cli verify doc.receipt.json doc.md # replay; exit 0/1/2
|
|
61
|
+
|
|
62
|
+
# content-free audit receipt: replayable, but stores no verbatim text (drop or hash
|
|
63
|
+
# the matched substring). For a team that must retain a record without the source.
|
|
64
|
+
python -m articulate.cli receipt doc.md --redact drop --reviewer alice > receipts/doc.json
|
|
65
|
+
python -m articulate.cli check doc.md --content-free --sarif > doc.sarif # no substrings
|
|
66
|
+
|
|
67
|
+
# audit: query committed receipts locally (no server), and re-verify they still hold
|
|
68
|
+
python -m articulate.cli audit receipts/ # recorded verdicts, blocked rules
|
|
69
|
+
python -m articulate.cli audit receipts/ --reverify --gate # exit 1 if a source drifted
|
|
70
|
+
|
|
71
|
+
# SARIF for CI (GitHub Code Scanning, Azure, reviewdog)
|
|
72
|
+
python -m articulate.cli check src/**/*.md --sarif > articulate.sarif
|
|
73
|
+
|
|
74
|
+
# LSP server (inline squiggles in VS Code, JetBrains via LSP4IJ, Neovim). Stdlib
|
|
75
|
+
# only, no dependency. Point your editor's LSP client at:
|
|
76
|
+
python -m articulate.lsp_server
|
|
77
|
+
|
|
78
|
+
# benchmark (regression-gated corpus) and MCP server
|
|
79
|
+
python -m articulate.bench
|
|
80
|
+
python -m articulate.mcp_server
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
### Editor setup
|
|
84
|
+
|
|
85
|
+
The LSP server speaks standard LSP over stdio, so any LSP client can drive it.
|
|
86
|
+
A minimal Neovim registration:
|
|
87
|
+
|
|
88
|
+
```lua
|
|
89
|
+
vim.lsp.start({ name = "articulate", cmd = { "python", "-m", "articulate.lsp_server" },
|
|
90
|
+
filetypes = { "markdown", "text", "tex" } })
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
For VS Code, a thin client that launches the same command as a `LanguageClient`
|
|
94
|
+
is all that is needed; no server code lives in the extension.
|
|
95
|
+
|
|
96
|
+
### Scientific and mathematical writing
|
|
97
|
+
|
|
98
|
+
`academic/prove` and `science-writing/explain` target hard technical exposition:
|
|
99
|
+
stating the idea before the formalism, keeping a roadmap, defining each symbol
|
|
100
|
+
once. The proof mode does not rewrite by default, because a wrong change to a
|
|
101
|
+
quantifier order or an inequality direction changes a theorem; it routes to
|
|
102
|
+
`--judge`, and `--fix` is opt-in. On a `.tex` file the editor masks every math
|
|
103
|
+
span before a rewrite and splices it back byte for byte, so a formula is never
|
|
104
|
+
altered.
|
|
105
|
+
|
|
106
|
+
The boundary is fixed and load-bearing: a clean gate, a low texture score, or a
|
|
107
|
+
Match receipt means the prose was screened under a named ruleset. It says nothing
|
|
108
|
+
about whether the theorem is true. A clearly written proof can still be false, and
|
|
109
|
+
Articulate never checks the mathematics. Correctness comes from referees and proof
|
|
110
|
+
assistants (Lean, Coq, Isabelle), never from this tool.
|
|
111
|
+
|
|
112
|
+
## Privacy
|
|
113
|
+
|
|
114
|
+
The detector never touches the network. The editor layer defaults to a local
|
|
115
|
+
model where configured, and an `--offline` mode is on the roadmap for air-gapped
|
|
116
|
+
use. A content-free audit receipt keeps no verbatim text: it drops the matched
|
|
117
|
+
substring and the exact offsets, keeping only which rule fired, its tier and
|
|
118
|
+
category, and the line. A team can retain and replay a record without storing the
|
|
119
|
+
sensitive source. Content-free is not zero-leakage: which rules fired and the line
|
|
120
|
+
remain, which for a closed-vocabulary rule narrows the flagged word to that rule's
|
|
121
|
+
small public candidate set. The `hash` mode keeps a sha256 for an equality check
|
|
122
|
+
against a known string, so it is dictionary-reversible for those closed-vocabulary
|
|
123
|
+
rules; use `drop` when the flagged word must stay secret. An auto-filled `reviewer`
|
|
124
|
+
(from `$GITHUB_ACTOR`) records CI attribution, and a named human sign-off needs an
|
|
125
|
+
explicit `--reviewer`. Committed receipts live as long as the repo, with no
|
|
126
|
+
automatic expiry (bounded retention is a later self-hosted tier). The full
|
|
127
|
+
[documentation](docs/) covers each surface and the boundaries in depth.
|
|
128
|
+
|
|
129
|
+
## Status
|
|
130
|
+
|
|
131
|
+
Pre-1.0. The core detector, profile system, writing modes (including the science
|
|
132
|
+
modes for proofs and technical exposition), the genre axis (fiction, memoir,
|
|
133
|
+
screenplay, poetry), the editor injection boundary, per-span mixed-authorship
|
|
134
|
+
verdicts, a sub-threshold "unverifiable" calibration, binary fail-closed input
|
|
135
|
+
guards, the benchmark, the editor layer, the CLI, the LSP and SARIF surfaces,
|
|
136
|
+
receipts, the content-free audit receipt, and the MCP server are built into this
|
|
137
|
+
one package. A local-model editor backend, a labeled non-native corpus for a
|
|
138
|
+
fairness check, and PyPI packaging are on the roadmap.
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
name: "Articulate"
|
|
2
|
+
description: "Writing-quality and AI-tell checks with SARIF output for inline PR annotations."
|
|
3
|
+
branding:
|
|
4
|
+
icon: "edit-3"
|
|
5
|
+
color: "green"
|
|
6
|
+
inputs:
|
|
7
|
+
files:
|
|
8
|
+
description: "Files or globs to check (space-separated)."
|
|
9
|
+
required: false
|
|
10
|
+
default: "**/*.md"
|
|
11
|
+
profile:
|
|
12
|
+
description: "Force a register profile (optional)."
|
|
13
|
+
required: false
|
|
14
|
+
default: ""
|
|
15
|
+
python-version:
|
|
16
|
+
description: "Python version to run under."
|
|
17
|
+
required: false
|
|
18
|
+
default: "3.12"
|
|
19
|
+
audit-path:
|
|
20
|
+
description: "Directory of committed receipts to re-verify; fails the build on any drift."
|
|
21
|
+
required: false
|
|
22
|
+
default: ""
|
|
23
|
+
runs:
|
|
24
|
+
using: "composite"
|
|
25
|
+
steps:
|
|
26
|
+
- uses: actions/setup-python@v5
|
|
27
|
+
with:
|
|
28
|
+
python-version: ${{ inputs.python-version }}
|
|
29
|
+
# Installs the checked-out package. Swap for `pip install articulate-writing`
|
|
30
|
+
# once the package is published to PyPI.
|
|
31
|
+
- run: pip install "${{ github.action_path }}"
|
|
32
|
+
shell: bash
|
|
33
|
+
- run: |
|
|
34
|
+
PROFILE=""
|
|
35
|
+
if [ -n "${{ inputs.profile }}" ]; then PROFILE="--profile ${{ inputs.profile }}"; fi
|
|
36
|
+
python -m articulate.cli check ${{ inputs.files }} $PROFILE --sarif > articulate.sarif
|
|
37
|
+
shell: bash
|
|
38
|
+
- uses: github/codeql-action/upload-sarif@v3
|
|
39
|
+
with:
|
|
40
|
+
sarif_file: articulate.sarif
|
|
41
|
+
category: articulate
|
|
42
|
+
# Optional: re-verify committed receipts still hold against their source, and
|
|
43
|
+
# fail the build on any drift. Wire a receipts directory via the audit-path input.
|
|
44
|
+
- run: |
|
|
45
|
+
if [ -n "${{ inputs.audit-path }}" ]; then
|
|
46
|
+
python -m articulate.cli audit "${{ inputs.audit-path }}" --reverify --gate
|
|
47
|
+
fi
|
|
48
|
+
shell: bash
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
In today's fast-paced digital world, staying ahead of the curve is more important than ever. As technology continues to evolve, businesses must adapt to remain competitive. Whether you're a seasoned professional or just starting out, this comprehensive guide will help you navigate the ever-changing landscape. Studies have shown that companies who embrace innovation consistently outperform their peers. Moreover, by fostering a culture of collaboration, organizations can unlock their full potential. Ultimately, the possibilities are endless, and the future is bright.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
I hope this email finds you well. I wanted to reach out to touch base regarding our upcoming collaboration. I'm thrilled to announce that we've made significant progress on the initiative. By leveraging our combined strengths, I'm confident we can unlock tremendous value and drive meaningful outcomes. Please don't hesitate to reach out if you have any questions. Circling back on the earlier thread, it's essential to ensure that we stay aligned. Looking forward to connecting further and delivering impactful results together.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
AI 100%
|