AE5VG

Field Guide · September 2026

The Operating Skills

This guide covers the operating skills that come with fldigi-mcp and n3fjp-mcp. They teach an agent to key the transmitter and return to receive the moment an over ends. They also teach it to run a contest QSO from CQ to a logged contact, and to cope with what a real band throws at it. Every rule in this guide was tested on the air.

Operating skills3
Rules in the standard6
Special cases handled7
Worked examples from the air3

Field-proven at ARRL Field Day 2026 · Class 2A · BPSK31

A · Skills at a glance

There are three skills. The table shows what each one governs and what you get from it.

#SkillShips withWhat it governsWhat you get
01fldigi-operatingfldigi-mcpThe 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.
02contest-operatingn3fjp-mcpThe 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.
03signal-huntingfldigi-mcpThe 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.
Proposed, not yet in fldigi

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.

Who reads these skills

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)

  1. Install the bundles. Double-click fldigi-mcp.mcpb and n3fjp-mcp.mcpb, or add them under Settings → Extensions. Each bundle carries its skill at skills/<name>/SKILL.md plus this guide.
  2. 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

  1. Copy the skill directories from each repo into ~/.claude/skills/, or a project's .claude/skills/: skills/fldigi-operating/, skills/signal-hunting/ and skills/contest-operating/.
  2. 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.

Untested outside Claude

Other assistants and harnesses have not been tested, and there are no ready-made configurations for them yet.

Check that it works (thirty seconds)

  1. Check the radio link. Ask "What is the fldigi status?" Mode, frequency and T/R state should come back. If not, the diagnostics tool tells you whether it is a network problem before you blame fldigi.
2 · Dry-run the handoff: this keys the transmitter

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.

Good to know

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

  1. 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.
  2. 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.
  3. 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 with n3fjp-mcp.mcpb. You only do this once.
  4. 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 typeWhat 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.
stopTransmission stops immediately and the radio returns to receive. This works at any moment, even in the middle of an over.
You are still the control operator

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.

First time? Dummy load, then the air.

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.

1 · CQ2 · Exchange3 · TU4 · Log anyone out there?caller decoded, send oursthey QSL, confirm theirs backwrite it, then QRZ CQ FD CQ FD de <MYCALL> <MYCALL> pse k <CALL> de <MYCALL>Pse copy 2A 2A STX STXde <MYCALL> BK QSL <CLASS> <SECT> TU <CALL>de <MYCALL> GL FD sk sk log → log_qso … check logged: true then QRZ, back to CQ
The four-state loop: CQ (anyone out there?), Exchange (caller decoded, send ours), TU (they QSL, confirm theirs back), Log (write it, then QRZ).
  • 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 ^r handoff 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 first contact

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.

  1. 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 (via transmit → 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.
  2. 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.
  3. 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.
  4. Trust only logged: true. N3FJP's ENTERRESPONSE can report 0 for a QSO that was written (networked mode commits asynchronously). Retrying every time records_added: 0 came back produced duplicate log records. Retry only when logged is false.
  5. 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.
  6. Send twice anything that must get through QRM. Send 2A 2A STX STX and 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.
Why this exists

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

Ships with fldigi-mcp

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)
This keys the transmitter

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.

OperationBehaviorUse for
^r via transmit → sendGraceful auto-return the moment the over ends.Every normal over.
transmit → abortImmediate stop, discards queued text.The panic button: caller back early, wrong message, operator says stop.
transmit → rxReturns 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_length for the end position, then text → read from your last position. Save the new position.
  • Watch for a restart. If rx_length is smaller than your last position, fldigi has restarted. Take the new length as your starting point and continue.
  • Listen window. After get_trx_status returns "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
The loop keys the transmitter

Every pass sends a CQ on the air. Stay at the station while it runs. "stop" drops PTT at once.

Skill 02 · contest-operating

Ships with n3fjp-mcp

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 STX copies far better than 2A STX through 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.

Avoiding duplicate log records

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

Ships with fldigi-mcp

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.

FieldMeaning
carrier_hzThe audio carrier: where the waterfall cursor goes. fldigi's Freq is dial plus carrier.
mode, fldigi_modemRTTY with its shift, CW, BPSK31/63/125, Olivia with tones and bandwidth (OLIVIA-8/250), MFSK16, DominoEX, MT63, or unknown.
db_over_floorStrength, from a max-hold spectrum, so a station that transmits for part of the window still shows at full strength.
persistenceFraction 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.
periodicityHow strongly the on-off pattern repeats at lags of 8 to 60 seconds. A CQ loop repeats; a QSO in progress does not.
scoreStrength weighted by persistence and periodicity. The station calling CQ scores highest.

With the Signal Browser patch

Proposed, not yet in fldigi

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

Proposed, not yet in fldigi

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
Current limits

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.

SituationWhat the agent does
Callsign only, no exchangeThis is normal. Send your exchange, and theirs arrives in the next over.
Exchange arrives with the first callThis 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 callsignSend 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 doubledYou see interleaved callsigns and control garbage. Send one AGN, then CQ. Usually one of them calls again alone.
Another station CQing on frequencyWith 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-QSOThe exchange was never completed, so do not log it. An incomplete QSO is not a contact.
Field note · N3FJP modal dialogs

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

TX CQ FD CQ FD de K6ABC K6ABC pse k RX K6ABC de W7XYZ 1D AZ; 1D AZ PSE K caller sent callsign and full exchange up front; no need to ask TX W7XYZ de K6ABC K6ABC · Pse copy 2A 2A STX STX · de K6ABC BK RX K6ABC QSL TU 73 de W7XYZ · GL es 73 · sk TX QSL 1D AZ TU W7XYZ de K6ABC GL FD sk sk logged while the TU was still transmitting: log_qso → logged: true

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

TX CQ FD CQ FD de K6ABC K6ABC pse k RX **4* K6ABr DE N4DEF N4DEet N4DEF callsign only, repeated three times through light garble, readable; no exchange yet: normal, not an error TX N4DEF de K6ABC K6ABC · Pse copy 2A 2A STX STX · de K6ABC BK RX **** K6ABC · QSL PSE COPY 1D 1D NFL DE N4DEe K their QSL and exchange arrive together in the second over TX QSL 1D NFL TU N4DEF de K6ABC GL FD sk sk

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

TX CQ FD CQ FD de K6ABC K6ABC pse k RX 6ABC de K0GHI K0GH · pse cpy 1E UT 1E UT TX K0GHI de K6ABC K6ABC · Pse copy 2A 2A STX STX · de K6ABC BK RX nt z repeat no cpy they did not copy us; resend once, abbreviated (playbook, row 3) TX K0GHI de K6ABC · 2A STX 2A STX · BK RX cptt t te e t eg TX K0GHI de K6ABC AGN pse k RX (silence, two listen windows) TX CQ FD CQ FD de K6ABC K6ABC pse k

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
Only logged: true means success

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 → calltab can trigger an ENTEREVENT directly (the band, mode and dupe check fires on callsign entry). If it does, the QSO is logged. Do not send another enter.
  • calltab also fills in the COUNTRY, STATE and section lookups. Use them to check that the section you copied is plausible for the callsign.
  • A CALLTABDUPEEVENT means 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 exchange dict of log_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.

ResourceWhere
fldigi-mcpgithub.com/sbrunner-atx/fldigi-mcp · PyPI: fldigi-mcp
n3fjp-mcpgithub.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 reportn3fjp-mcp/docs/LESSONS-FIELD-DAY-2026.md

Corrections and additions are welcome. Open an issue on either repository.

73

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.