Evidence-backed application prep for academic and professional jobs.
Project description
这也能投/CanISend
Evidence-backed application prep for academic and professional jobs. CLI/package name: canisend.
这也能投是一款 local-first CLI:从职位广告和本地私人履历证据出发,生成可检查的申请材料包,包括 parsed criteria、fit report、cover letter draft、CV tailoring notes、material checklist 和 Typst-ready source。强主张应当能追溯到本地证据。
It prepares materials only. It does not submit applications, create accounts, fill portals, scrape full job pages, upload packages, or answer sensitive declarations.
What It Does
- Creates a private workspace for profile evidence, job folders, prompts, Typst templates, schemas, and agent instructions.
- Imports and filters jobs.ac.uk RSS leads without scraping full job pages.
- Creates one local folder per application, with the full advert kept as a manual input.
- Extracts normalized evidence from Typst-first profile sources into
profile/generated/. - Generates
parsed_job.json, fit reports, cover letter drafts, CV tailoring notes, criteria checklists, material review checklists, and structured Typst content. - Runs deterministic local generation by default, with explicit opt-in for LLM-backed evidence augmentation, parsing, or drafting.
- Ships bridge files for Codex, Claude Code, and IDE agents through
AGENTS.md,CLAUDE.md, andagent-skills/canisend/SKILL.md.
Quick Start
Choose one installation method. CanISend requires Python 3.11 or newer.
Install as an isolated CLI with uv
Use this after the production release is available on PyPI:
uv tool install canisend
Install as an isolated CLI with pipx
If you prefer the pip ecosystem but still want an isolated command-line tool:
pipx install canisend
Install with pip in a virtual environment
Use this when you want CanISend available inside a project-specific Python environment:
python -m venv .venv
source .venv/bin/activate
python -m pip install --upgrade pip
python -m pip install canisend
Install the current TestPyPI beta
For the current beta, install canisend==0.2.0b10 from TestPyPI while still resolving dependencies from PyPI:
uv tool install \
--index-url https://test.pypi.org/simple/ \
--extra-index-url https://pypi.org/simple/ \
canisend==0.2.0b10
Or with pip inside an active virtual environment:
python -m pip install \
--index-url https://test.pypi.org/simple/ \
--extra-index-url https://pypi.org/simple/ \
canisend==0.2.0b10
Run the packaged fake-data workflow before using private profile or job data:
canisend run-example --workspace /tmp/canisend-example --overwrite
Inspect the generated dossier:
/tmp/canisend-example/jobs/2026-06-15_example-university_lecturer-in-applied-economics/
parsed_job.json
02_fit_report.md
03_cover_letter_draft.md
05_criteria_checklist.md
07_material_review_checklist.md
typst/
From a development checkout, prefix CLI commands with uv run:
uv run canisend --help
uv run canisend run-example --workspace /tmp/canisend-example --overwrite
Core Workflow
private profile -> generated evidence -> job folder -> parsed criteria
| |
v v
item-level receipts draft materials + review checklist
| |
+------------ manual review -----------+
1. Initialize a private workspace
Normal users should install the CLI and keep private application data in a separate workspace. They do not need to fork this repository.
canisend init-workspace --workspace ~/CanISendWorkspace
canisend doctor --workspace ~/CanISendWorkspace
The workspace contains private profile data, job leads, job folders, editable prompt copies, Typst templates, schemas, examples, and agent-readable skills:
~/CanISendWorkspace/
canisend.yaml
.env.example
.gitignore
AGENTS.md
CLAUDE.md
profile/
jobs/
job_leads/
prompts/
templates/
schemas/
agent-skills/
After upgrades:
uv tool upgrade canisend
canisend update-workspace --workspace ~/CanISendWorkspace
canisend doctor --workspace ~/CanISendWorkspace
update-workspace preserves local prompt, template, and skill edits by default. Use --overwrite only when packaged defaults should replace local copies.
If doctor reports deprecated packaged files from an older release, remove only those retired defaults with:
canisend update-workspace --workspace ~/CanISendWorkspace --prune-deprecated
doctor also reports local default resources that differ from the packaged version. Use update-workspace --overwrite only after deciding those local prompt, template, schema, or bridge edits should be replaced.
2. Prepare profile evidence
Put your real modernpro CV and statements under ~/CanISendWorkspace/profile/typst/. These files stay local, and profile/ is ignored by git except for .gitkeep.
Create starter profile files if needed:
canisend init-profile --workspace ~/CanISendWorkspace --mode typst
Generate normalized evidence:
canisend extract-profile-evidence --workspace ~/CanISendWorkspace
When local Typst extraction misses evidence, you can explicitly opt into provider-backed augmentation:
canisend extract-profile-evidence \
--workspace ~/CanISendWorkspace \
--llm-augment
The profile manifest lives at profile/profile.yaml. Generated evidence is written to profile/generated/ and cited with item-level references such as:
profile/generated/cv.evidence.md#Teaching/cv-001
Review item-level evidence citations before trusting any generated claim.
3. Import leads and create one job folder
Fetch jobs.ac.uk RSS leads locally:
canisend fetch-jobs-ac-uk \
--workspace ~/CanISendWorkspace \
--feed-url "<jobs.ac.uk RSS url>" \
--include economics \
--exclude phd
Create a job folder from a selected zero-based lead index:
canisend new-job-from-lead \
--workspace ~/CanISendWorkspace \
--lead-index 0 \
--institution "University X" \
--deadline "2026-06-15"
You can also create a job manually:
canisend new-job \
--workspace ~/CanISendWorkspace \
--title "Lecturer in Economics" \
--institution "University X" \
--deadline "2026-06-15" \
--source-url "https://www.jobs.ac.uk/job/example"
Paste the full advert into jobs/<job-slug>/job_advert.md before relying on parsed criteria or generated drafts. V1 does not scrape full job pages.
4. Generate draft materials
Run the deterministic local pipeline:
canisend run \
--workspace ~/CanISendWorkspace \
--job jobs/<job-slug>
Generated output includes:
jobs/<job-slug>/
parsed_job.json
01_job_summary.md
02_fit_report.md
03_cover_letter_draft.md
04_cv_tailoring_notes.md
05_criteria_checklist.md
06_final_application_package.md
07_material_review_checklist.md
typst/
cover_letter.typ
application_package.typ
Generated Typst files are the editable source of truth for final formatting. Content JSON files may still be emitted as compatibility/debug artifacts, but normal edits should happen in the .typ files.
To track edits to generated application materials in a private git repository, opt in after generation:
canisend run \
--workspace ~/CanISendWorkspace \
--job jobs/<job-slug> \
--git-add-materials
Without the flag, interactive terminals are asked whether to add generated application materials to git; non-interactive runs skip git staging unless the flag is set. CanISend stages only the generated fit report, cover letter draft, CV tailoring notes, criteria checklist, final package, material review checklist, and editable Typst sources. It does not stage raw adverts, source URLs, parsed job JSON, compatibility JSON, PDFs, or profile files, and it never commits automatically.
LLM-backed evidence augmentation, parser, and draft generation are explicit opt-in modes. Configure a provider before using them:
ACADEMIC_PREP_LLM_PROVIDER=openai-compatible
OPENAI_API_KEY=...
OPENAI_BASE_URL=https://api.openai.com/v1
OPENAI_MODEL=...
canisend extract-profile-evidence \
--workspace ~/CanISendWorkspace \
--llm-augment
canisend run \
--workspace ~/CanISendWorkspace \
--job jobs/<job-slug> \
--llm-parser \
--llm-drafts
For local CLI model access, use the command provider:
ACADEMIC_PREP_LLM_PROVIDER=command
ACADEMIC_PREP_LLM_COMMAND="codex exec --json"
ACADEMIC_PREP_LLM_TIMEOUT_SECONDS=300
The LLM-backed evidence augmenter only accepts items tied to a supporting source_text found in the local profile source. The LLM-backed parser must return JSON matching the parsed_job.json contract. Draft outputs must cite profile evidence; unknown citations fail validation. Missing evidence should be marked as a gap, not replaced with unsupported claims.
5. Review, render, and submit manually
Review files in this order:
parsed_job.json05_criteria_checklist.md02_fit_report.md03_cover_letter_draft.md04_cv_tailoring_notes.md07_material_review_checklist.mdtypst/cover_letter.typtypst/application_package.typ06_final_application_package.md
Use 07_material_review_checklist.md to track the cover letter draft, CV tailoring notes, placeholders, item-level evidence citation checks, and next manual actions.
After reviewing the Markdown drafts, directly edit typst/cover_letter.typ and typst/application_package.typ for final wording and layout. The files include stable // CANISEND: section ... markers so agents can make bounded edits without rewriting the whole Typst source.
Run a read-only package check before treating generated materials as ready for user review:
canisend check-package \
--workspace ~/CanISendWorkspace \
--job jobs/<job-slug>
The check reports missing package files, invalid generated Typst sources, unresolved bracketed placeholders, and unknown profile evidence citations. It does not generate or modify files.
Render Typst only when needed:
canisend render-typst \
--workspace ~/CanISendWorkspace \
--job jobs/<job-slug>
Rendering requires a local typst binary. Source generation does not. Submit manually through the institution portal outside this tool.
Agent Usage
Codex, Claude Code, and IDE agents can run the canisend workflow by opening the private workspace as the project root. This is an agent-assisted workflow, not a local-only workflow: any file, PDF, webpage, or generated material the agent reads or summarizes may be processed by the agent model provider.
- Codex and AGENTS.md-aware tools should read
AGENTS.md. - Claude Code should read
CLAUDE.md, which importsagent-skills/canisend/SKILL.md. - IDE agents can read
AGENTS.mdand thenagent-skills/canisend/SKILL.md.
Agents should start with:
canisend doctor --workspace .
They may run local deterministic CLI commands, inspect generated evidence, and review current job artifacts. They must ask first before reading full private CVs, statements, full job adverts, references, PDFs, source URLs, generated packages, or enabling LLM-backed CLI flags/providers. They must not scrape pages, submit applications, upload packages, fabricate evidence, or commit private profile/job data.
For coordinated multi-CLI review, use canisend orchestrate with an explicit local YAML plan:
canisend orchestrate \
--workspace ~/CanISendWorkspace \
--job jobs/<job-slug> \
--plan orchestration.yaml \
--dry-run
Worker entries declare command, max_parallel_tasks, supports_native_subagents, and privacy_tier_limit. Task entries declare role, inputs, outputs, writes, depends_on, privacy_tier, and optional agent_count for CLIs that can run several native subagents under one task. The orchestrator runs dependency-ready tasks in parallel, enforces worker concurrency limits, writes run artifacts under jobs/<job-slug>/orchestration/runs/, and requires --allow-private-sources or --allow-provider-backed for higher privacy tiers.
Privacy modes:
- Direct CLI deterministic mode can be local-only when no agent reads private content and no LLM flags/providers are used.
- Agent-assisted mode means agent-read content may enter the agent model context.
- LLM-backed CLI mode means selected context may be sent to the configured provider or local command through flags such as
extract-profile-evidence --llm-augment,--llm-parser, or--llm-drafts.
Detailed agent guidance lives in:
agent-skills/canisend/
SKILL.md
references/
workflow.md
job-lifecycle.md
file-contracts.md
typst-profile.md
provider-config.md
quality-gates.md
agent-orchestration.md
platforms.md
privacy.md
prompts/ contains LLM prompt files used by the application pipeline. agent-skills/ contains agent-readable workflow and quality guidance.
Skill Distribution
The project also ships a reusable skill pack for cases where you want a narrower agent behavior without opening a CanISend workspace as the active project. The root Codex plugin manifest at .codex-plugin/plugin.json exposes skills/ as a Codex plugin manifest, while the original agent-skills/canisend/ workspace skill remains unchanged.
Use the main canisend skill for full workspace and job-package workflows. Use material-specific skills for focused tasks such as canisend-research-statement, canisend-cover-letter, canisend-cv-tailoring, canisend-criteria-check, and canisend-material-review.
For a Codex marketplace repository, mount this repository as the plugin source:
git submodule add https://github.com/jxpeng98/CanISend plugins/canisend
Then add a marketplace entry that points to ./plugins/canisend.
To export skills from an installed package instead of a checkout:
canisend export-skills --target ~/plugins/canisend --kind codex-plugin
canisend export-skills --target ~/.claude/skills --kind skills-only
codex-plugin writes .codex-plugin/ plus skills/. skills-only writes only the skill folders for agents that install skills directly.
Privacy Boundaries
This repository is intended to be open source. Personal application data should stay local:
profile/is ignored by git except for.gitkeep.jobs/generated job folders are ignored by git unless selected generated materials are explicitly staged withcanisend run --git-add-materials.job_leads/RSS outputs are ignored by git..env, API keys, rendered PDFs, raw job adverts, real source URLs, parsed job JSON, and profile files should not be committed.- Sensitive declarations such as right-to-work, visa, disability, equality monitoring, health, criminal record, and conflicts remain user-only.
这也能投只是材料准备工具,不是提交凭证。
Maintainer Release
Release automation lives in GitHub Actions for jxpeng98/CanISend.
Local checks:
uv run python -m pytest -v
uv build
uvx twine check dist/*
uv run python -m canisend.package_check dist/*.whl
CI runs the same test/build/resource-check sequence on pushes and pull requests. The release workflow uses PyPI Trusted Publishing with OIDC:
- Pushing
test/v<version>publishes to TestPyPI only. - Pushing
v<version>bNorv<version>rcNpublishes to TestPyPI, smoke-tests the TestPyPI package, then publishes a PyPI prerelease and creates a GitHub prerelease. - Pushing
v<version>publishes to TestPyPI, smoke-tests the TestPyPI package, then publishes a stable PyPI release and creates a GitHub Release. - TestPyPI and PyPI need a Trusted Publisher for
.github/workflows/release.ymlwith environments namedtestpypiandpypi.
Preferred tag-driven release orchestration:
scripts/release.sh test --version 0.2.0.dev1
scripts/release.sh beta --version 0.2.0b1
scripts/release.sh stable --version 0.2.0
The script updates pyproject.toml and src/canisend/__init__.py, runs local checks, commits the version bump, pushes the current branch, then creates and pushes the matching git tag:
git tag -a test/v0.2.0.dev1 HEAD -m "canisend 0.2.0.dev1 TestPyPI"
git tag -a v0.2.0b1 HEAD -m "canisend 0.2.0b1 beta"
git tag -a v0.2.0 HEAD -m "canisend 0.2.0 stable"
release.yml is the only remote publisher. It always publishes to TestPyPI first, and only promotes v* tags to beta or stable PyPI after the TestPyPI publish and smoke test succeed.
Use test/v* with a disposable version because TestPyPI package versions cannot be overwritten.
Use RELEASE.md for the full TestPyPI and PyPI release playbook. Version updates must change both pyproject.toml and src/canisend/__init__.py.
Repository Layout
src/canisend/ CLI and application pipeline
prompts/ LLM prompt templates
templates/typst/ modernpro Typst templates
schemas/ JSON schema contracts
agent-skills/ canisend skill and agent references
skills/ reusable Codex and Claude skill pack
.codex-plugin/ Codex plugin manifest for the skill pack
platform-bridges/ AGENTS.md and CLAUDE.md workspace bridges
examples/end_to_end/ fully local fake-data workflow
tests/ CLI, pipeline, packaging, release, and contract tests
assets/ project logo and README media
RELEASE.md maintainer release playbook
See canisend_v1_proposal.md for the original V1 engineering proposal.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file canisend-0.2.0b10.tar.gz.
File metadata
- Download URL: canisend-0.2.0b10.tar.gz
- Upload date:
- Size: 176.9 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
1c123d9b53318ce7757b909e7411f1de5515c34b871b478d2d71a1707e6d1ff3
|
|
| MD5 |
0deed361c62df3fa9a948a8165332e85
|
|
| BLAKE2b-256 |
ec3cbbd652316f5e7401f6b8bb76020d0e69567d1da1aa2e693513fd8f270dd7
|
Provenance
The following attestation bundles were made for canisend-0.2.0b10.tar.gz:
Publisher:
release.yml on jxpeng98/CanISend
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
canisend-0.2.0b10.tar.gz -
Subject digest:
1c123d9b53318ce7757b909e7411f1de5515c34b871b478d2d71a1707e6d1ff3 - Sigstore transparency entry: 1909031799
- Sigstore integration time:
-
Permalink:
jxpeng98/CanISend@5e588ab5efe98ffc35276417f1613a893b5d0614 -
Branch / Tag:
refs/tags/v0.2.0b10 - Owner: https://github.com/jxpeng98
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@5e588ab5efe98ffc35276417f1613a893b5d0614 -
Trigger Event:
push
-
Statement type:
File details
Details for the file canisend-0.2.0b10-py3-none-any.whl.
File metadata
- Download URL: canisend-0.2.0b10-py3-none-any.whl
- Upload date:
- Size: 124.9 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
d5a8df192c426974e2b9976e2df88654da1498e430e796f794d7eaedbea2fc9e
|
|
| MD5 |
6fc8e6cbd9d9b7d7ec30f940a7b57673
|
|
| BLAKE2b-256 |
d735bde3b3015b662fbd8e474cb9c8c8050de34203fd6f148210894fada76ea8
|
Provenance
The following attestation bundles were made for canisend-0.2.0b10-py3-none-any.whl:
Publisher:
release.yml on jxpeng98/CanISend
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
canisend-0.2.0b10-py3-none-any.whl -
Subject digest:
d5a8df192c426974e2b9976e2df88654da1498e430e796f794d7eaedbea2fc9e - Sigstore transparency entry: 1909031926
- Sigstore integration time:
-
Permalink:
jxpeng98/CanISend@5e588ab5efe98ffc35276417f1613a893b5d0614 -
Branch / Tag:
refs/tags/v0.2.0b10 - Owner: https://github.com/jxpeng98
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@5e588ab5efe98ffc35276417f1613a893b5d0614 -
Trigger Event:
push
-
Statement type: