A · Skills at a glance
There are three skills. The table shows what each one governs and what you get from it.
| # | Skill | Ships with | What it governs | What you get |
|---|---|---|---|---|
| 01 | fldigi-operating | fldigi-mcp | The radio: keying the transmitter, returning to receive the instant an over ends, and polling the RX stream so no caller is missed. | Instant TX to RX handoff, and a caller never ignored. |
| 02 | contest-operating | n3fjp-mcp | The contest: the QSO state machine from CQ to logged contact, the special-case playbook, and verified N3FJP logging. | Completed exchanges, and a clean, duplicate-free log. |
| 03 | signal-hunting | fldigi-mcp | The band: naming each signal's mode from the audio, ranking the station that sits still and calls CQ, tuning to it, and reading fldigi's Signal Browser where the proposed browser.* patch is present. | The right station found, named and tuned before you call. |
The browser.* and rsid.* methods that skill 03 can use come from two patches offered upstream on w1hkj/fldigi issue 55. Neither patch is merged yet. The section on skill 03 has the details.
You do not invoke these skills by name. The agent does, when you say things like "call CQ on 20 meters" or "run the Field Day loop". The skills are the agent's operating procedures. This guide is for the human at the station. It explains what the agent will do for you and how to check that it is doing it right.
B · Installing the skills
Each skill comes inside its MCP package. When you install the server, you get the skill with it. There is nothing to configure separately.
In Claude Desktop (.mcpb bundle, recommended)
- Install the bundles. Double-click
fldigi-mcp.mcpbandn3fjp-mcp.mcpb, or add them under Settings → Extensions. Each bundle carries its skill atskills/<name>/SKILL.mdplus this guide. - Set the transmit gate. In the fldigi-mcp extension settings, enter your callsign. With no callsign set, the station is receive-only and nothing can key the radio.
Cowork and Claude Code sessions inside the Claude Desktop app use these same extensions. Nothing else to install.
For advanced users: Claude Code in a terminal, or another MCP client
- Copy the skill directories from each repo into
~/.claude/skills/, or a project's.claude/skills/:skills/fldigi-operating/,skills/signal-hunting/andskills/contest-operating/. - Connect the MCP servers (
uvx fldigi-mcp,uvx n3fjp-mcp, or from the repos) so the tools the skills reference are available.
The MCP servers and skills are not tied to Claude. MCP is an open standard, so other assistants and agentic harnesses such as OpenClaw should work too.
Other assistants and harnesses have not been tested, and there are no ready-made configurations for them yet.
Check that it works (thirty seconds)
- Check the radio link. Ask "What is the fldigi status?" Mode, frequency and T/R state should come back. If not, the
diagnosticstool tells you whether it is a network problem before you blame fldigi.
With the radio on a dummy load, type "send TEST DE <YOURCALL> and return to receive". fldigi should key, send, and drop PTT on its own, with no carrier left on.
fldigi's default XML-RPC port is 7362. If a different port is configured (7372, for example), you are usually meant to go through a forwarder such as mcp-host-bridge, which passes traffic from localhost to the remote machine. Check FLDIGI_PORT before you decide fldigi is down.
C · Your first session with Claude
You do not need to know anything about AI to run this station. If you can install fldigi and type a sentence, you can operate it. This chapter covers everything you need to learn.
What you are installing
Claude is an assistant made by Anthropic. It runs in an ordinary desktop program, the Claude Desktop app (Windows or Mac). The app looks like a messaging window. You type at the bottom and the answers appear above. Think of the two MCP servers in this project as rig-interface cables. One connects Claude to fldigi, the other connects it to N3FJP. You type plain English and Claude works the programs. Your fldigi and N3FJP setup does not change. Both programs run as they always have.
Setup, once
- Install the Claude Desktop app. Download it from
claude.ai/download, install it like any other program, and sign in (you can create the account on the same page). A paid plan is recommended, because the free tier can run out of messages in the middle of a QSO. - Run your shack software as usual. Start fldigi (its XML-RPC interface is on by default). If you want contest logging, start N3FJP and enable its TCP API (Settings → Application Program Interface → checked). fldigi must key the radio the usual way, under Configure → Config Dialog → Rig Control: Hardware PTT for an interface such as a RigBlaster, nothing for a VOX interface such as a SignaLink. If fldigi's T/R button keys the radio, Claude can too. The N3FJP loggers run only on Windows. On a Mac, run N3FJP in a Windows virtual machine or on a Windows PC, and connect it with mcp-host-bridge, as Getting Started shows.
- Add the two extensions. Double-click
fldigi-mcp.mcpb, click Install when Claude Desktop opens, and enter your callsign when asked. That callsign is the transmit gate. Repeat withn3fjp-mcp.mcpb. You only do this once. - Say hello. Open a new chat and type: "What is the fldigi status?" If mode, frequency and T/R state come back, your station is connected.
Operating is a conversation
There are no commands or syntax to learn. You type what you would tell a competent operator sitting at your rig.
| You type | What happens |
|---|---|
| What is the fldigi status? | Mode, frequency, T/R state and callsign gate. This is your pre-flight check. |
| Set the rig to 14.070 USB and BPSK31. | Claude QSYs the rig and sets the modem. |
| Call CQ Field Day until someone answers. Work them, our exchange is 2A STX, log the contact to N3FJP, then keep calling. | The full loop in this guide: CQ, listen, exchange, TU, log, repeat. Claude narrates each QSO as it happens. |
| stop | Transmission stops immediately and the radio returns to receive. This works at any moment, even in the middle of an over. |
Claude operates the station, but you hold the license. Part 97 responsibility remains yours: supervision, station identification, and staying in the band. It is the same as having a guest operator at your key. Stay at the station while it transmits. There are two built-in safeguards. With no callsign configured, the station physically cannot key up. And "stop" always works.
Start on a dummy load and test only the transmit side. Type "call CQ once, then listen" and check that the rig keys, sends and drops back to receive, with no carrier left on. Nobody can answer a dummy load, so there is no QSO and no log entry yet. Then connect the antenna, start the loop, and watch the first contact all the way into the log. If anything misbehaves, type "run the fldigi diagnostics" and read the answer. It tells you whether the problem is in the network or in fldigi.
D · How the system works
A QSO is a loop with four states. fldigi-operating governs the radio in every state. contest-operating decides what to say and when to log.
- Skills respond to plain language. There are no commands to memorize. Say "call CQ until someone answers, then work them and log it" and both skills come into play. You can also ask for a skill by name when you want that skill applied.
- The radio layer comes first, because everything above it depends on it. An over that does not drop PTT on time sends idle carrier on top of the answering station. No exchange strategy can recover from that. The
^rhandoff is not optional. - The two skills work in sequence. fldigi-operating sends clean overs and reads the RX stream as it arrives. contest-operating takes that stream, runs the exchange, and passes a confirmed QSO to the logger. If a callsign comes through garbled, the result is an AGN request, not a log entry.
- The operator remains in command. Say "stop" at any time. That runs
transmit → abort, which drops PTT immediately and discards queued text. Without a configured callsign, the station cannot transmit at all.
Watch the loop once before you trust it. A dummy load only proves the transmit side: the CQ, the drop back to receive, and "stop". The rest needs a real station, so on the air watch the first complete QSO: TX drop, listen window, exchange, log entry.
E · The operating standard
Both skills follow these six rules. We broke each of them once, on the air, at Field Day 2026. That is why each rule exists.
- Never poll the TX buffer to decide when to stop. fldigi is designed to hold PTT on an empty buffer. End every over with
^r(viatransmit → send), and fldigi drops to receive on the sample where the last character finishes. Polling always lags, and the lag goes out on the air on top of your caller. - The RX buffer never contains your own echo. Every character in it came from another station. If your callsign shows up in RX, someone is calling you, so answer them. Logic that dismisses your call as "own echo" makes you ignore callers. We wrote that logic, it ignored callers, and we deleted it.
- Never log without a confirmed callsign. Class and section can be inferred from a repeat, but a callsign cannot. An incomplete QSO is not a contact. Abandon it and call CQ again.
- Trust only
logged: true. N3FJP's ENTERRESPONSE can report 0 for a QSO that was written (networked mode commits asynchronously). Retrying every timerecords_added: 0came back produced duplicate log records. Retry only whenloggedis false. - Give an unreadable station two overs at most. Send one AGN and allow one listen window. If it is still garbled, go back to CQ. Five minutes spent on a marginal signal is four QSOs you did not make.
- Send twice anything that must get through QRM. Send
2A 2A STX STXand your callsign twice on CQ. Echo the other station's exchange back in your TU so they can check what you logged before you QRZ.
We built these skills by running one real autonomous Field Day session and keeping the after-action report. The full account is in n3fjp-mcp/docs/LESSONS-FIELD-DAY-2026.md. The worked examples in chapter G retell it verbatim.
Skill 01 · fldigi-operating
This skill governs the radio. It transmits, hands off to receive, and listens properly.
Transmitting an over
transmit → send "<over text>\n" (return_to_rx=true, the default)
transmit → send puts the station on the air. It refuses unless a callsign is set, and transmit → abort is always allowed.
This one call clears the TX buffer, appends ^r, and keys the radio. End messages with a real newline (\n). The two-character string ^n goes out literally, as those two characters. If you build an over in pieces with text → add_tx, the last piece must end in ^r, and nothing may be added after it.
| Operation | Behavior | Use for |
|---|---|---|
| ^r via transmit → send | Graceful auto-return the moment the over ends. | Every normal over. |
| transmit → abort | Immediate stop, discards queued text. | The panic button: caller back early, wrong message, operator says stop. |
| transmit → rx | Returns to RX only after the buffer drains. | Almost never. It is slow, and it is not the stop button. |
Listening
- Read only the new text. Call
text → rx_lengthfor the end position, thentext → readfrom your last position. Save the new position. - Watch for a restart. If
rx_lengthis smaller than your last position, fldigi has restarted. Take the new length as your starting point and continue. - Listen window. After
get_trx_statusreturns"rx", listen about 10 seconds (1 to 2 polls) before the next CQ. PSK31 operators type slowly. - Validate callsigns against
[A-Z0-9]{1,3}[0-9][A-Z]{1,3}before any directed reply. QRM garbage can look like a callsign.
loop:
transmit → send "CQ CQ de <MYCALL> <MYCALL> pse k\n"
poll controls → get_trx_status until "rx"
listen ~10 s (1-2 polls of text → rx_length)
if plausible callsign in new RX text → work the station
else → loop
Every pass sends a CQ on the air. Stay at the station while it runs. "stop" drops PTT at once.
Skill 02 · contest-operating
This skill governs the contest. It decides what to say in each state, when a QSO is real, and when it goes in the log.
Sending the exchange
- Send everything important twice.
2A 2A STX STXcopies far better than2A STXthrough QSB and QRM. - Echo their exchange back in the TU (
QSL 1D AZ TU W7XYZ …). The other station can then check that you logged them correctly before you QRZ. - Callsign-only callers are normal. Some operators send just their call and wait. Send your exchange, and theirs arrives in the next over. Others send everything up front. Then you go straight to TU after your exchange.
- Log while the TU is still transmitting. The radio is busy for about 15 seconds, which is the time logging takes. When TX drops, you are ready to call CQ.
Logging the contact
log → log_qso {"call": "W7XYZ", "contest": "field_day",
"exchange": {"class": "1D", "section": "AZ"}}
Exchange fields go in the exchange dict, not in top-level parameters. The QSO is logged when the response says logged: true. Chapter H has the full protocol and its quirks.
Never retry on records_added: 0 alone. The value can be 0 for a QSO that was written. Retry only when logged is false. Blind retries are what cause duplicate log records.
Skill 03 · signal-hunting
This skill finds a station worth working, the same way an operator reads the waterfall. It names what is there and ranks the station that sits still and calls CQ highest. Then it tunes to that station and confirms it within twenty seconds.
Two ways to hunt
The preferred way reads fldigi's own Signal Browser. It needs no audio setup, but it needs a patched fldigi (see With the Signal Browser patch, proposed and not yet in fldigi). Until the patch is in fldigi, use the sound bridge: signal_hunt listens to the same receiver audio as fldigi. With the radio on a sound card cable (an iMic, a SignaLink, the radio's USB port), set Audio input device to the device fldigi uses, because two programs can read one input at once. When the receiver audio plays on the computer (an SDR program, a web receiver, wfview), split it with a virtual sound card: BlackHole 2ch and a Multi-Output Device on a Mac, or VB-Audio Virtual Cable on Windows. Getting Started has the steps.
What the tool sees
fldigi's XML-RPC interface does not give access to the spectrum. So signal_hunt listens to the same audio fldigi is listening to (the Audio input device setting names it) and returns a ranked list of candidates. It needs the optional extra fldigi-mcp[hunt] (numpy and sounddevice). Each candidate tells you where the cursor goes, what modem to run, and why it ranks where it does.
| Field | Meaning |
|---|---|
| carrier_hz | The audio carrier: where the waterfall cursor goes. fldigi's Freq is dial plus carrier. |
| mode, fldigi_modem | RTTY with its shift, CW, BPSK31/63/125, Olivia with tones and bandwidth (OLIVIA-8/250), MFSK16, DominoEX, MT63, or unknown. |
| db_over_floor | Strength, from a max-hold spectrum, so a station that transmits for part of the window still shows at full strength. |
| persistence | Fraction of the window the signal was present at that carrier. A CQ loop is near 1; the other side of a QSO comes and goes. |
| periodicity | How strongly the on-off pattern repeats at lags of 8 to 60 seconds. A CQ loop repeats; a QSO in progress does not. |
| score | Strength weighted by persistence and periodicity. The station calling CQ scores highest. |
With the Signal Browser patch
The browser tool and signal_hunt method="browser" call two XML-RPC methods that stock fldigi does not have: browser.get_channels (one struct per channel: channel, freq, active, text) and browser.clear. They come from a four-file patch offered to Dave W1HKJ on 11 September 2026 (w1hkj/fldigi issue 55) and shipped in fldigi-mcp under patches/. Until he merges it, the names and fields are a proposal and may change. On an unpatched fldigi both calls answer with a hint, and nothing else in this chapter changes.
fldigi's own Signal Browser, the left-hand panel, is a bank of thirty demodulators with DCD. It copies PSK, RTTY and CW stations that are too faint for any spectrum to rank. On a build with the patch, browser channels or signal_hunt method="browser" returns every channel with its carrier and the text copied so far, with line breaks kept. So the confirm step is already done before you tune. In a test with four synthetic PSK31 stations from 0 to −26 dB, all four were copied in full. The browser does not name the mode, so hunt the audio first when you do not know the band's mode. Building the patched fldigi yourself takes three lines, given in the README.
Letting the station name its own mode
The rsid tool calls rsid.get_hits and rsid.clear, from a second four-file patch offered to Dave W1HKJ on 16 September 2026 (w1hkj/fldigi issue 55). It ships in fldigi-mcp under patches/ and applies on top of the browser patch. Until it is merged the names and fields are a proposal. On an unpatched fldigi the tool answers with a hint, and nothing else in this chapter changes.
For the hopping modes, naming a mode from its shape is guesswork. Olivia and Contestia share a grid, and so do THOR and DominoEX. Most operators on those modes send an RSID burst at the start of an over. fldigi's detector hears that burst anywhere in the passband. Set RxID to notify only. The detector then reports the mode without switching the modem, so the pass you are running keeps its browser. rsid hits gives {utc, mode, hz} for every burst. You can pass the mode name straight to tune_to, and the frequency is where the cursor goes. Check the RSID hits before you guess the mode, especially when the analyzer says unknown on a strong signal.
How a mode is named
The tool names a mode from the signal's shape, the way you would from the waterfall. The numbers were checked against the Signal Identification Wiki. Two narrow lines a standard shift apart (170 Hz in amateur use) are RTTY, with the carrier at the midpoint. One 30 Hz line is PSK31, unless it is keyed on and off with gaps of 40 ms or more, which makes it CW. The hopping modes show up as a grid of separate dots when you track where the energy is from one 30 ms frame to the next. For Olivia, tones = bandwidth / spacing. MFSK16 has 16 tones at 15.6 Hz. DominoEX and THOR have 18 tones. MT63 is a flat, continuous block. Contestia looks like Olivia, and THOR looks like DominoEX. Only RSID tells those pairs apart. The full signature table is on the Mode ID page.
The loop
signal_hunt seconds=20 (contest: mode="RTTY", seconds=40)
read candidates highest score first
tune_to carrier_hz, fldigi_modem (RxID off during a classified pass)
wait 20 s, then text → read
if CQ and a callsign-shaped token, twice → hand to fldigi-operating
elif modem → get_quality below 30 → next candidate
else a QSO in progress → wait for SK or 73
So far the mode naming has been tested on five recordings of known mode: PSK31, CW, RTTY at 170 and 450 Hz, and Olivia 8/250. It named all five correctly. That is a small set, so treat an unknown result as a real answer. The tool does not measure symbol rate yet. Symbol rate is what would separate Contestia from Olivia without RSID. Without audio access, the tool falls back to stepping fldigi's own search_up and reading get_quality. That is slow, and it cannot tell the mode. Hunting only listens. Nothing in this skill keys the transmitter.
F · The special-case playbook
We ran into all seven of these on the air at Field Day 2026.
| Situation | What the agent does |
|---|---|
| Callsign only, no exchange | This is normal. Send your exchange, and theirs arrives in the next over. |
| Exchange arrives with the first call | This is also normal (K6ABC de W7XYZ 1D AZ 1D AZ pse k). Send yours, they QSL, and you go straight to TU. |
| "No copy" / "repeat" | Resend once, abbreviated: <CALL> de <MYCALL> · 2A STX 2A STX · BK. If there is still nothing, QRZ once, then CQ. |
| Garbled or partial callsign | Send de <MYCALL> AGN AGN pse k and allow one listen window. If it is still unreadable, go back to CQ. Two overs at most. |
| Two stations doubled | You see interleaved callsigns and control garbage. Send one AGN, then CQ. Usually one of them calls again alone. |
| Another station CQing on frequency | With PSK's narrow signals, you also decode neighbors in the passband. CQ … de <OTHERCALL> is not a caller. Ignore it and continue. |
| Signal lost mid-QSO | The exchange was never completed, so do not log it. An incomplete QSO is not a contact. |
A modal dialog on the logging PC blocks the entire N3FJP API. If logging calls stop responding mid-contest, a dialog is open. A person has to close it. The agent cannot clear it remotely.
G · Worked examples from Field Day
These are three real QSOs from the session log on 14.070 MHz BPSK31, transcribed as decoded, garble included. All callsigns are anonymized (ARRL-style sample calls) out of respect for the stations worked. The exchanges, the flow and the garble are verbatim.
Example 1 · W7XYZ, the textbook QSO
Logged, 1D AZ. Copy was clean both ways. The exchange was confirmed in both directions in one pass through the state machine.
Example 2 · N4DEF, callsign first, exchange after
Logged, 1D NFL. The state machine handles an exchange that arrives one over late. The callsign was confirmed before anything was logged.
Example 3 · K0GHI, no copy, abandoned correctly
Not logged. We never confirmed that they copied our exchange. Rule 3 of the standard says an incomplete QSO is not a contact. We spent two overs on it, then went back to calling CQ.
H · Logging to N3FJP
This is the logging protocol we verified, with every quirk we hit on the air.
Preferred: log_qso
log → log_qso {"call": "W7XYZ", "contest": "field_day",
"exchange": {"class": "1D", "section": "AZ"}}
Manual alternative
log → set_many {"CALL": "W7XYZ", "CLASS": "1D", "SECTION": "AZ"}
log → enter
Both paths return a logged value, true or false. It is worked out from the change in the QSO count, from an ENTEREVENT push, or from both. records_added can report 0 for a QSO that was written, because N3FJP networked (master-table) mode commits asynchronously. Retry only when logged is false.
Quirks, observed live
set_many → calltabcan trigger an ENTEREVENT directly (the band, mode and dupe check fires on callsign entry). If it does, the QSO is logged. Do not send anotherenter.calltabalso fills in the COUNTRY, STATE and section lookups. Use them to check that the section you copied is plausible for the callsign.- A
CALLTABDUPEEVENTmeans the call is already in the log for this band and mode. Usually that means you, or a retry, already logged it. - Exchange fields belong in the
exchangedict oflog_qso. If you pass them as top-level parameters, nothing is logged and no error is shown.
I · About and provenance
These skills were not designed on paper. They were written from one real autonomous contest session.
At ARRL Field Day 2026, a class-2A club station ran 20-meter BPSK31 with an agent operating fldigi and N3FJP through fldigi-mcp and n3fjp-mcp: calling CQ, working callers, and logging contacts, with the human operator supervising and able to stop transmission at any moment. Every rule, timing and special case in this guide comes from that session's after-action report, n3fjp-mcp/docs/LESSONS-FIELD-DAY-2026.md.
| Resource | Where |
|---|---|
| fldigi-mcp | github.com/sbrunner-atx/fldigi-mcp · PyPI: fldigi-mcp |
| n3fjp-mcp | github.com/sbrunner-atx/n3fjp-mcp · PyPI: n3fjp-mcp |
| Skill sources | <repo>/skills/<name>/SKILL.md |
| This guide's sources | <repo>/docs/brand/ (HTML and CSS, WeasyPrint) |
| After-action report | n3fjp-mcp/docs/LESSONS-FIELD-DAY-2026.md |
Corrections and additions are welcome. Open an issue on either repository.
This is private, personal work by Stefan Brunner, AE5VG, built for amateur radio operators. It is not affiliated with fldigi, N3FJP, or any employer. GPL-3.0-or-later, like fldigi itself. GL es 73 de AE5VG sk.