get-fsa-training-done
One agent skill, and the CLI behind it, for getting FSA training done: designing a programme, writing its teaching material, and designing and grading its assessments. It installs into Claude Code, Codex (the app, the CLI and the IDE extension), GitHub Copilot (the Copilot CLI and agent mode in VS Code) and Antigravity (the app and the IDE).
The landing page shows
how it works, in real files; its source is in docs/.
The skill has three features, each with its own CLI namespace:
| Namespace | What it does | Docs |
|---|---|---|
program |
design a training programme and export its workbooks | README |
material |
write slide decks on the FSA template, one lecture note per module and lab guides in HTML, and export them to .pptx and .pdf |
README |
assessment |
design and grade quizzes, assignments, exams and capstones | README |
They divide one job. A programme's session plan names, in its
Training Materials column, the file that serves each session — so program
declares that a slot exists and what it weighs, material writes the slides,
note or lab guide, and assessment writes the quiz, brief or exam. No feature
authors another's artifact, and each checks its own half of that manifest.
The skill is built from tasks — one step each, such as writing a rubric, rendering a brief, or merging a retake — composed into workflows. Ask for a whole job and the agent follows the workflow; ask for one step and it runs that task on its own.
The skill is stateless. It assumes nothing about the directory layout it was installed into and never scans a project on a hunch — it asks for its inputs first, echoes back the resolved paths, and waits for a go-ahead.
Install
pip install get-fsa-training-done
This gives you the gftd command, which every example below uses; it is also
installed under its full name, get-fsa-training-done.
It needs Python 3.12+.
Then install the skill into your agent:
gftd install
In a terminal this asks which agents to install to (↑↓ to move, space to select, enter to confirm) and whether globally or for this project, shows an installation summary, and writes nothing until you answer yes. Nothing starts ticked.
The skill is written once, to .agents/skills/get-fsa-training-done —
~/.agents/skills globally, ./.agents/skills for a project. Codex and GitHub
Copilot read that folder directly, and Antigravity does for a project; every
other agent gets a symlink to it, so one update reaches all of them. Where the
system refuses symlinks (Windows without Developer Mode) that agent gets its
own copy instead.
| Agent | Global | Project |
|---|---|---|
| Codex | ~/.agents/skills/… |
./.agents/skills/… |
| GitHub Copilot | ~/.agents/skills/… |
./.agents/skills/… |
| Claude Code | ~/.claude/skills/… → link |
./.claude/skills/… → link |
| Antigravity | ~/.gemini/config/skills/… → link |
./.agents/skills/… |
Releases before this one wrote Codex to ~/.codex/skills and ./.codex/skills
and Copilot to ~/.copilot/skills and ./.github/skills. gftd update moves
such an install to .agents/skills, so the agent does not load the skill twice.
| Command | Effect |
|---|---|
gftd install |
ask which agents and where, then install |
gftd install --platform all --scope user |
every agent, globally, without asking |
gftd install --platform claude --scope project |
Claude Code, for this project, without asking |
gftd pack |
the skill as a zip, for a hosted agent that takes an upload (see below) |
gftd update |
upgrade the CLI from PyPI, then every install it finds, preserving files you edited |
gftd uninstall |
show every install and what goes, then remove all of it on yes |
gftd status |
what is installed where, and whether it drifted |
gftd doctor |
check this machine for the skill's prerequisites |
Give --platform or --scope and install asks nothing; outside a terminal
(CI, a pipe) it installs for Claude Code globally. --yes skips the questions.
uninstall is all or nothing — the agents share one copy, so it cannot be
taken from just one of them — and outside a terminal it needs --yes.
Add --dry-run to any of install, update, or uninstall to see the exact
file-by-file plan without touching anything.
gftd update first upgrades the package itself to the latest PyPI release —
through pip, pipx or uv tool, whichever installed it — then updates the skill
in every agent and scope that holds an install (--platform/--scope narrow
that). --no-self-update, --offline or
GET_FSA_TRAINING_DONE_NO_SELF_UPDATE=1 skip PyPI; an editable checkout is
never upgraded, only reported.
Hosted agents (Claude Managed Agents)
A hosted agent such as Claude Managed Agents takes a skill as an upload, not a folder on your machine. Pack it:
gftd pack # writes get-fsa-training-done-<version>.zip
Each GitHub release also carries that zip. Upload it on the Claude Console's
Skills page (or POST /v1/skills, or unzip it and ant apply the folder),
then add it to the agent under Skills as a custom skill.
hosted/ holds the rest, ready to copy: the agent's system prompt
and settings as an ant apply file, its environment, and the instructions for
Microsoft Copilot Studio.
The sandbox has Python, but not this skill's CLI. The first time the agent
needs the CLI, the skill runs its own scripts/setup.sh, which installs
get-fsa-training-done at the skill's version from PyPI and builds the
workers' environment, so the agent's environment must reach PyPI. The Console
creates environments with Limited networking; allow package managers:
name: fsa-training
config:
type: cloud
networking:
type: limited
allow_package_managers: true # pypi.org and files.pythonhosted.org
The agent also needs its bash tool, which the default toolset includes. A
surface whose sandbox has no network at all — code execution in the Messages
API — can read the skill but cannot install the CLI, so its commands do not run there.
Dependencies
Installing the package pulls nothing: dependencies = [] is deliberate, so the
lifecycle commands run on a bare interpreter. The libraries the worker commands
need live in the managed virtualenv instead — declared once in
src/get_fsa_training_done/lifecycle/envmgr/requirements/core.txt:
| Library | Used by |
|---|---|
xhtml2pdf |
assessment render, for the brief PDF |
py7zr |
assessment grade preprocess, for .7z submissions |
gftd install builds that environment, so the first install
needs a network and everything after it does not — which is the property that
matters on an exam machine.
Two external tools are optional, and doctor reports each without failing for
its absence:
- A
.rarextractor (unar,7zorbsdtar)..raris proprietary and has no pure-Python reader; every other archive format is read in-process. - Docker, for
assessment sandbox: running a seed script, a JUnit suite or a pytest run that is not ours — an exam's supplied files, or a submission — in a disposable container with no network.
Rendering embeds its own fonts (see
features/common/render/fonts/), so a
Vietnamese brief comes out identical on every machine.
Layout
src/get_fsa_training_done/
cli.py skill.py the CLI, and the one skill it installs
lifecycle/ install, update, uninstall, status, doctor, env
features/ program, material, assessment (+ common)
payload/get-fsa-training-done/
SKILL.md the router: workflows and tasks per feature
references/<feature>/ overview, tasks/, workflows/, generated references
references/common/ writing style, Vietnamese conventions, shared tasks
Development
pip install -e .
pytest
ruff check . && ruff format --check .
python scripts/sync_version.py --check
for generator in scripts/*/gen_*.py; do python "$generator" --check; done
src/get_fsa_training_done/__about__.py holds the canonical version;
sync_version.py propagates it to the payload's VERSION.
Testing the skill from source
gftd update installs the payload of whichever package gftd runs from, so
point gftd at the checkout and update:
pip install -e . # replaces a PyPI install of the package
gftd update # copies src/.../payload/ into every install it finds
An editable checkout is never upgraded from PyPI, only reported, and the worker
commands run the checkout's code too. The payload is copied, not linked: run
gftd update again after each payload change (--dry-run shows the plan,
--force overwrites files edited in place, keeping *.bak).
To go back to a released version:
pip uninstall -y get-fsa-training-done # drops the editable .pth
pip install get-fsa-training-done # or ==<version> to pin one
gftd update # syncs the installs to that payload
Add --no-self-update to that last update when you pinned an older version,
or it upgrades to the latest release. gftd --version and gftd status
confirm what is running and whether the installs match it.
Releasing
A release is a pushed v<version> tag; nothing else publishes. Ordinary
commits stay on the current version.
# 1. bump the canonical version, then propagate it
$EDITOR src/get_fsa_training_done/__about__.py # __version__ = "X.Y.Z"
python scripts/sync_version.py
# 2. run every gate in "Development" above — CI runs the same ones
# 3. commit, tag, push the commit and the tag together
git commit -am "Release X.Y.Z"
git tag -a vX.Y.Z -m "vX.Y.Z"
git push origin main vX.Y.Z
The tag triggers .github/workflows/release.yml:
- guard — refuses the tag unless it equals
v+__about__.py's version, and re-runs the version and generated-file gates. - pypi — builds, checks the wheel carries the skill payload, and
publishes through PyPI Trusted Publishing (environment
release; no token). - github-release — creates the GitHub release with generated notes and
attaches the skill as a zip (
gftd pack), for hosted agents.
The landing page reads the latest version from PyPI, so it needs no edit.
Users pick the release up with gftd update, which upgrades the package from
PyPI and then every installed skill.
If the guard fails, the tag is wrong, not the workflow: delete it
(git push origin :refs/tags/vX.Y.Z && git tag -d vX.Y.Z), fix, and tag
again. Once PyPI has accepted a version it can never be re-uploaded — ship a
fix as the next patch version instead.
Licence
MIT
Metadata
Release files for get-fsa-training-done 2.8.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| get_fsa_training_done-2.8.0.tar.gz | 2.4 MB | With provenance | Details for get_fsa_training_done-2.8.0.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| get_fsa_training_done-2.8.0-py3-none-any.whl | Python 3 | none | any | Details for get_fsa_training_done-2.8.0-py3-none-any.whl |
Total release size: 4.7 MB
Release files / get_fsa_training_done-2.8.0.tar.gz
| Download URL | get_fsa_training_done-2.8.0.tar.gz |
|---|---|
| Size | 2.4 MB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
b5d794a2cc4447518eedf174ead10accd63fe576df00be53b733f9e433165a5b
|
|
BLAKE2b-256 checksum How to use checksums |
e8a468448fda428790df235202362bf581e3517ed84f1b8163d42fbf60b17893
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 31, 2026.
Transparency logRelease files / get_fsa_training_done-2.8.0-py3-none-any.whl
| Download URL | get_fsa_training_done-2.8.0-py3-none-any.whl |
|---|---|
| Size | 2.4 MB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
cef0ee03d343503fc2bdd4ae62c8fd96913cb538ae4ae53f73ff072d2e557f53
|
|
BLAKE2b-256 checksum How to use checksums |
90ef0d5b9bb36eabc3cfddd271f453bdd713606d260cf2536c36a513c7b919ae
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 31, 2026.
Transparency logSecurity for get-fsa-training-done 2.8.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
Full provenance
All 2 files in this release have been uploaded with provenance metadata.
Attestation for get_fsa_training_done-2.8.0.tar.gz
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 31, 2026.
Transparency logA note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.