Repository navigation
Releases: aacanadaa/packet-tracer-pkt-format
Release list
0.4.0
A pip install can now build a lab, not only read one.
pip install --upgrade packet-tracer-pkt-formatA pip install can now build a lab, not only read one.
Added
pkt_core.builder— theLabauthoring API, ported into the package from
tools/lab_api.py: place a device, set power, install a module, cable copper or
serial, write an IOS running-config, assign PC addressing, and save.pkt_core.resources— the bundled template library (137 device models, 78
modules) and the seed document, loaded throughimportlib.resourcesand cached.
This is what removes the checkout requirement.from pkt_core import Lab, Layout, load_templates;Lab()andload_templates()
with no arguments use the bundled data.tests/test_resources.py, covering the loaders and a full build-and-decode round
trip from the packaged data alone.
Changed
tools/lab_api.pyis now a compatibility shim re-exportingpkt_core.builder, so
thetools/scripts and anything doingimport lab_apifrom a checkout keep
working.- The few call sites that reached through
lab_api.pt9now use
lab_api.decode_bytes/encode_bytes.
Notes
- The port is behaviour-preserving: the
Labcode is unchanged apart from the codec
calls, which now go to the package instead of the rootpt9module. pkt_core.builderis not yet annotated internally and is therefore excluded
frommypy --strictinpyproject.toml, with the reason recorded there. Its
public signatures are typed, and every other module remains fully checked. The
remaining work is tracked inBUILDER_PORT.md.- The wheel grows by the two bundled assets (~1.9 MB raw). Scored-activity authoring
from the package (tools/activity.py,tools/scoring.py) is not ported yet.
from pkt_core import Lab
lab = Lab()
lab.prune_seed_devices()
r = lab.add_device("2911", "R1", 250, 350, install="HWIC-2T")
sw = lab.add_device("2960-24TT", "SW1", 450, 350)
lab.link(r, "GigabitEthernet0/0", sw, "GigabitEthernet0/1")
lab.save("lab.pkt")0.3.0
First release under the packet-tracer-pkt-format name:
https://pypi.org/project/packet-tracer-pkt-format/
pip install packet-tracer-pkt-formatWhat this fixes
The published package was hard to install and harder to find. In order:
pydanticwas an undeclared runtime dependency.pkt_core.modelsimports it,
pyproject.tomldid not list it, so a cleanpip install -e .raised
ModuleNotFoundErroronfrom pkt_core.models import Lab— the first line of the
README's own example.- The PyPI page linked nowhere. No homepage, no repository, no issue tracker. The
package and its source were invisible to each other in both directions. - The README never mentioned the package. It documented
python3 pt9.pyand a
root-only install, so the install path and the documentation described different
products. - Three CLI examples did not run.
pkt export -f graphvizis--format graphviz;pkt pack out/takes an XML file, not a directory. - A console script that could never resolve.
pt9 = "pt9:main"pointed at
src/pt9.py, which does not exist — the module is at the repository root. - A false dependency claim.
libgcryptwas presented as required and
root-installed; it is an optional accelerator, and the pure-Python path is
verified.
What is unchanged
The format work itself: encode(decode(f)) == f byte-for-byte on all 1,058 corpus
files, PT 4.1 through 9.0.1, both container families. 535 tests pass, mypy --strict is clean, coverage 91.3%.
Known limitation
A clean pip install can read, diff, audit and export, but not yet generate —
the authoring API and the four template assets still live in tools/ and need a
checkout. That is the next release; see BUILDER_PORT.md.
Verification
pip install packet-tracer-pkt-format
pkt info your_lab.pkt
pkt unpack your_lab.pkt -o out/
pkt pack out/your_lab.xml -o rebuilt.pkt # byte-identical to the originalSKILL.md v1.3.0 — rules 7 and 8: cables, and port names that kill the file
SKILL.md v1.3.0 — rules 7 and 8, from a build that passed every gate
A second large lab was built on this toolkit: an automated container terminal,
386 devices, 380 links, 15,345 config lines. It passed every gate this
repository documented — layout, audit, distinct counts, byte-exact round-trip —
and was still broken in two ways those gates cannot see.
Rule 7 — a cable is not a configuration
link() draws the cable and sets the port's electrical properties. It does not
give the interface a state.
| Defect | Count | Cause |
|---|---|---|
cabled ports with no interface block |
87 | L3-to-L3 links drawn with link() instead of rlink(). One core router had no interface blocks at all for either uplink |
| ports administratively shut | 5 | a blanket interface Ethernet0/0 / shutdown also shut each firewall's outside port |
| links whose ends disagreed on trunk/access | 45 | core-switch trunks covering the routed ports; downlinks declared access against a trunk |
The fix is structural — each port's role is derived from the peer it is cabled
to — and it is now gated, because discipline drifts.
Rule 8 — one bad port name makes the whole file unopenable
Not one dead cable. Packet Tracer refuses the entire document, with a message
that names no device, no port and no reason:
Unable to open file. The file ... is not compatible with this version of
Cisco Packet Tracer
Three names the reference corpus "attested" are rejected by PT 9.0.1:
| Model | Corpus says | PT 9.0.1 accepts |
|---|---|---|
7960 IP phone |
FastEthernet0 |
Switch (uplink), PC (passthrough) |
Cloud-PT |
GigabitEthernet0 |
Port 0 |
WLC-3504 |
GigabitEthernet0/1 |
GigabitEthernet1 |
Corpus frequency is evidence of what some older Packet Tracer wrote, not of
what this one accepts.
Two new gates
| # | Command | Proves |
|---|---|---|
| 0 | tools/audit_links.py |
every cabled port is brought up by the configuration that ships with it. Static, no Packet Tracer |
| 5 | tools/pt_accept.py |
Packet Tracer actually opens it — verdict read from the window title, run with a known-good control |
Both are standalone and need no cooperation from a generator, which is what makes
them real checks rather than restatements of intent. On the repaired build:
380 links, 0 findings, and sabotaging a single no shutdown makes gate 0 name
the device, port and peer.
Also in this release
ENGINE/TYPEtext is the device class (MultiLayerSwitch); the model is
themodel=attribute. Reading the text silently misses every port-table
lookup — and did, producing "28 models of interest, all zero" that looked like a
successful run.- The reference corpus cannot attest industrial/IoT models. A full mine of 952
files found zero instances ofIE-9320,IE-3400,PLC-PT,HMI-PT,
RFID Readeror any sensor family. 28 device classes in total. .ptdtemplates decode but carry no port names — only module types.- Template service blocks ship
<ENABLED>1</ENABLED>. After the records
were correctly stripped, 52 devices still advertised themselves as NTP servers. - DHCP and AAA identities are document-wide; DNS is per server. One
authoritative server per service, or the count is a lie either way. - The page, not the device count, bounds scale.
analyse()requires the
primary page andLayoutgives each tier its own band, so tier count is the
lever: ~26 rows atROW_PITCH = 150. - A new section on driving Packet Tracer's GUI under Xvfb — keyboard
accelerators do not work, the toolbar zoom-out is at x=450 (clicking 384 zooms
in and produces a blank workspace that reads like a render failure), resize
before zooming out, and two startup prompts make a successful load look like a
timeout.
New: docs/ENTERPRISE_PROBLEMS_YAMLT.md
The second problem catalogue — 21 entries with status, cause and probe,
matching the format of the JASDF one. It records the dead ends too: OCR of the
rejection modal reports rejected files as accepted; rapid successive Packet
Tracer launches raise a spurious "Incompatible File"; and 300 red pixels that
survived the cabling fix turned out to be the Trip Sensor and ASA 5505 icons,
not links.
Cost, before and after
| before | after | |
|---|---|---|
audit_links findings |
— | 0 of 380 |
| cabled ports with no interface block | 87 | 0 |
| red link-indicator pixels | 4538 | 300 (all device artwork) |
Both critical classes were invisible to every gate v1.2.0 documented.
SKILL.md v1.2.0 — authoring Packet Tracer labs that actually work
SKILL.md is the packaged agent skill for building Cisco Packet Tracer .pkt
labs and scored .pka activities offline, using this repository as the
toolkit. It is written to be usable on its own: if an agent has only this file,
its first section tells it how to fetch and verify everything else.
Get it
$ curl -LO https://github.com/aacanadaa/packet-tracer-pkt-format/releases/download/v1.2.0/SKILL.md
$ sha256sum SKILL.md
77a72ba43dc530097bb235f3684ffd953d00c1d2e499a919248835c4c64bf334 SKILL.mdA SKILL.md.sha256 is attached alongside it.
Why this release exists
The skill was previously only reachable by cloning the repository. Publishing it
as an asset gives a stable, versioned URL for the one file an agent needs, and
pins the guidance that was learned the hard way: this release records the
38 distinct defects found by shipping a 290-device lab and then opening it
in Packet Tracer. They are catalogued with evidence in
docs/ENTERPRISE_PROBLEMS.md.
What the skill now covers
Six authoring rules, each derived from a real failure: inherit template
state instead of writing constants over it; compute coordinates instead of
placing by hand; make every printed count a count of distinct things;
sanitise every field you did not author; make every documented number
reproducible; and never let a presence check stand in for an authorship check.
A pre-ship gate checklist — the five commands that enforce those rules, with
what each proves and its real exit code. Notably audit_ios_commands.py exits
2, and only for a suspicious signature: unattested-but-plausible IOS lines
are reported and do not fail.
A false-alarms section, so an agent does not "fix" correct output: amber link
lights are spanning-tree convergence, red serial cables are how Packet Tracer
draws serial regardless of state, >75 s convergence on a large lab is
run-dependent, and a duplicate <NAME> in the physical tree is not a collision.
Verification guidance applied to the skill itself. Two statements in the
bootstrap were wrong and were caught by executing the snippets rather than
reading them: Lab is not exported from the pkt_core package root (it lives in
pkt_core.models), and the documented test counts were stale. The skill now
states 0 failures as the invariant and explains the skip count instead of pinning
a total that rots.
Verified, not asserted
Every claim above was reproduced on the shipped reference lab:
| Check | Result |
|---|---|
| Round-trip re-encode | byte-exact, 1,128,475 bytes |
| Rebuild from generator | reproduces the shipped artefact byte-for-byte (c40c1417…) |
| Layout gate | 290 devices, 0 label overlaps, 0 off-page, 0 coincident, NN min 114.0 |
| Service counts | all distinct — AAA 139/139, DHCP 131/131, DNS 496 raw / 248 distinct |
| IOS attestation | 1,058 corpus files, 235 signatures, 99 attested, 0 suspicious |
| Tests | 542 passed, 1 skipped, 35 deselected (pytest tests/) |
| Types | mypy --strict src/pkt_core clean (25 files) |
Also in this release (v1.1.0 → v1.2.0)
47 commits. Beyond the skill:
- Both container families are supported and documented — the modern
Crypto++ EAX/Twofish path (PT 5.3.3 → 9.0.1) and the legacy PT 5.x container —
with the version boundary corrected and a whole-corpus acceptance test. - Optional Rust cipher accelerator, plus pure-Python Twofish/Serpent/CAST-256
so nothing is required to author a file (Python 3.10+). - CI: tests,
mypy --strictand a 90% coverage gate on every push. - Licence corrected to GPL-3.0-or-later. Earlier releases of this project
were distributed under PolyForm Noncommercial; that is no longer the case, and
the git history was rewritten so no earlier licence is served atHEAD.
Commercial use is permitted under the GPL.
Licence
GPL-3.0-or-later. See LICENSE.