Install
$ agentstack add skill-kennethreitz-pytheory-skill-playing-guitar-with-pytheory ✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ✓ Network access No
- ✓ Filesystem access No
- ✓ Shell / process execution No
- ✓ Environment & secrets No
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
Verified badge
Passed review? Show it. Paste this badge into your README, it links to the public security report.
Reliability & compatibility
Declared compatibility
Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.
We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.
How agent discovery & health will work →About
Playing guitar (and strings) with PyTheory
PyTheory models the fretboard: chord shapes, fingerings, tablature, scale diagrams, alternate tunings, and chord identification — for guitar and ~20 other stringed instruments — plus a real-time tuner. The fretboard tools are pure Python (run a script or one-liner); the tuner is a CLI that listens to your mic.
If PyTheory isn't installed, prefer uv when available: uv pip install pytheory (or uv add pytheory in a uv project); otherwise pip install pytheory.
Fingerings, chord shapes & tab
from pytheory import Fretboard, Chord
fb = Fretboard.guitar()
print(fb.tab("Am")) # ASCII tablature for a chord (high e on top)
# A minor
# e|--0--
# B|--1--
# G|--2--
# D|--2--
# A|--0--
# E|--x--
shape = fb.chord("Am") # a Fingering object
shape.positions # (None, 0, 2, 2, 1, 0) — None = muted string
shape.string_names # ('E', 'A', 'D', 'G', 'B', 'e') — data model, low-to-high
print(shape.tab()) # same ASCII tab (always high-to-low display)
Fretboard.guitar()and friends build a fretboard;.chord("Cmaj7")returns
a Fingering, .tab("Cmaj7") returns the ASCII tab string directly.
.fingering(0, 2, 2, 1, 0, 0)builds aFingeringfrom explicit fret numbers
(low-to-high), e.g. to check a shape you have in mind.
- A
Fingeringhas.positions,.string_names,.tones,.tab(),
.identify(), and .to_chord().
> Charted-chord coverage: .chord()/.tab() look the name up in a library of > ~144 common voicings — every root in major, minor, 5, 6, 7, m7, > maj7, 9, m9, maj9, and dim. Names outside that set (e.g. sus4, > m7b5, aug, add9) raise KeyError. For those, either build the shape > yourself with .fingering(...), or work from the chord's notes via > Chord.from_symbol("F#m7b5") (see "Identify a chord"). CHARTS["western"].keys() > lists everything charted.
Other instruments
All take the same .chord() / .tab() / .scale_diagram() API:
Fretboard.bass() # E1 A1 D2 G2 (.bass(five_string=True) for a low B)
Fretboard.ukulele() # G4 C4 E4 A4
Fretboard.mandolin() # G3 D4 A4 E5
Fretboard.banjo() # open G 5-string
Also available: mandola, octave_mandolin, mandocello, violin, viola, cello, double_bass, harp, pedal_steel, oud, sitar, shamisen, erhu, charango, pipa, balalaika, lute, twelve_string.
Alternate tunings & capo
Fretboard.guitar(tuning="drop d") # named tunings
Fretboard.guitar(tuning="dadgad")
Fretboard.guitar().capo(2) # capo at the 2nd fret
Named guitar tunings: standard, drop d, open g, open d, open e, open a, dadgad, half step down. For anything else, pass a tuple of open-string notes (low-to-high), e.g. Fretboard.guitar(tuning=("C2","G2","C3","G3","C4","E4")).
Identify a chord
From notes:
Chord.from_symbol("F#m7b5").identify() # 'F# half-diminished 7th'
From a shape on the neck (great for "what chord is x02210?"):
fb = Fretboard.guitar()
fb.fingering(None, 0, 2, 2, 1, 0).identify() # 'A minor'
Scale diagrams
from pytheory import TonedScale, Fretboard
scale = TonedScale(tonic="E2", system="western")["minor"]
print(Fretboard.guitar().scale_diagram(scale, frets=5))
# 0 1 2 3 4 5
# E| E | - | F#| G | - | A |
# A| A | - | B | C | - | D |
# ...
> Pentatonic and blues scales live in the blues system, not western: > TonedScale(tonic="E2", system="blues")["minor pentatonic"] (also > "major pentatonic", "blues", "major blues").
Diagram images (SVG/PNG)
The ASCII diagrams above also render as clean SVG you can embed in a video, slide, or worksheet (roots in red; PNG needs the optional cairosvg):
from pytheory import Fretboard, TonedScale
fb = Fretboard.guitar()
# Chord box — open/muted markers, barres auto-detected
fb.tab_image("Am", "Am.svg")
for name in ["C", "Am", "F", "G"]: # iterate a whole set
fb.tab_image(name, f"{name}.svg")
fb.chord("Am").to_svg(path="Am.svg") # same, straight from a Fingering
# Scale position shapes — e.g. the five pentatonic boxes, roots marked
pent = TonedScale(tonic="A4", system="blues")["minor pentatonic"]
for shape in fb.scale_shapes(pent): # one box per position (1-based .index)
shape.to_svg(path=f"pos{shape.index}.svg")
# Arpeggio map — every chord tone across the neck, labelled R/3/5/7…
fb.arpeggio_diagram("Am", "Am_arp.svg")
tab_image() covers the same ~144 charted chords as .tab(); an uncharted name raises ValueError, so build the shape and call Fingering.to_svg() instead. Pass fmt="png" (or a .png path) to rasterize via cairosvg. Each call returns the SVG string, or the path when one is given.
Nashville number charts
from pytheory import Key
prog = Key("G", "major").nashville(1, 4, 5, 1)
[c.symbol for c in prog] # ['G', 'C', 'D', 'G']
Turn a melody into tab
Write a line as a part, print it as tablature for a guitarist:
from pytheory import Score, Duration
s = Score("4/4", bpm=120)
gtr = s.part("gtr", instrument="acoustic_guitar")
for n in ["E4", "G4", "A4", "B4", "D5", "E5"]:
gtr.add(n, Duration.QUARTER)
print(s.to_tab("gtr"))
# e|-0--3--5--7-|-10-12|
# B|------------|------|
# ...
Score.to_tab(part_name) accepts tuning= and frets= too.
Tune up — the real-time tuner
A CLI that listens to your microphone (the user runs it themselves — suggest the ! prefix so its output lands in the session):
$ pytheory tune --instrument guitar # strobe tuner locked to the 6 strings
$ pytheory tune --instrument guitar --chords # strum → it names the chord
$ pytheory tune --serve # browser strobe page + JS pitch stream
$ pytheory tune --ref 442 # different concert pitch
Instrument presets: guitar, bass, ukulele, violin, viola, cello, mandolin, banjo. To get the target frequencies programmatically:
from pytheory.tuner import string_targets
string_targets("guitar") # [('E2', 82.4), ('A2', 110.0), ('D3', 146.8), ...]
string_targets("guitar", reference_pitch=442) # shifted concert pitch
Tips & gotchas
.chord()returns aFingering;.tab()returns the printable string. Use
.tab() when you just want to show the user a chart.
- Muted strings are
Nonein.positionsandxin the tab. - Tunings are low-to-high tuples of open-string notes; capo with
.capo(n). - Pentatonic/blues scales are in the
bluessystem, notwestern. - The tuner needs a microphone, so it's a CLI the user runs (
pytheory tune),
not something to call from a rendering script.
- Composing a full arrangement (chords, drums, synths, MIDI/WAV export) is the
job of the composing-with-pytheory skill — this one is about the fretboard and tuning.
Source & license
This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: kennethreitz
- Source: kennethreitz/pytheory-skill
- License: MIT
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet, be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.