Feature Roadmap¶
What may come next. This page is a menu, not a schedule — an unchecked item is a candidate, not a commitment, and the order is not a queue.
For what 3270Web provides today, see Terminal Capabilities. That page is the one to read before an evaluation; this one is for deciding what to build.
The field, and where 3270Web sits in it¶
A roadmap is a set of choices, and the choices are made against a category that already exists. So the comparison comes first, and the rest of the page follows from it.
The table describes how each emulator is delivered and what it offers for automation — facts each vendor states plainly and that rarely change from release to release. It is deliberately not a feature-by-feature grid: nobody can honestly audit eight products from the outside, and a tick in a column you cannot verify is worse than no column at all. Each vendor's own documentation is the authority on that vendor's product. Rows were checked against published documentation in August 2026; if one is wrong or has gone stale, tell us and it gets fixed.
| Emulator | How it reaches the user | Runs on | Licence | Automation surface |
|---|---|---|---|---|
| 3270Web | A URL. One Go binary or container serves the terminal to a browser tab | Any modern browser; server on Linux, Windows, macOS or Docker | Open source (AGPL-3.0-or-later), commercial terms available | REST/JSON API, recorded workflows replayed as JSON, Guided Business Tasks, an HLLAPI-shaped endpoint, and an MCP server |
| Quick3270 | Installed Windows application | Windows client and server, Citrix and Terminal Server | Commercial, per seat | VBScript macro language with an editor and debugger, EHLLAPI (32- and 64-bit), a session API and COM automation |
| Vista TN3270 | Installed Windows application | Windows | Commercial, low per-seat fee | Fully tailorable keyboard, multiple paste buffers, JCL-aware selection — aimed at the programmer at the keyboard |
| Mocha TN3270 | Installed application, one per platform | Windows, macOS, ChromeOS, iOS, Android | Commercial, per seat | Keyboard definition and user-defined function keys |
| HCL Z and I Emulator for Web | Browser, served from an application server | Browser client; Windows, Linux or z server | Commercial, licensed per user | EHLLAPI and the host-access toolkit APIs, including a J2EE connector |
| Inventu Viewer+ (formerly Flynet Viewer) | Browser, served from a Windows server — no plug-in, no applet | Browser client; Windows Server | Commercial | Server-side screen integration, with generated web services |
| Ericom PowerTerm WebConnect HostView | Browser, served from a central server | Browser client; Windows or Linux server | Commercial | Centrally managed sessions, with scripting in the PowerTerm client |
| x3270 / wc3270 / c3270 / s3270 | Installed command-line or X11 application | Linux, Unix, Windows, macOS | Open source (BSD-3-Clause) | The s3270 scripting protocol — the same engine 3270Web drives |
Reading the table¶
Three delivery models, and which one a product picked decides most of everything else about it.
Installed desktop clients — Quick3270, Vista TN3270, Mocha TN3270 and the x3270 family — have the deepest terminal fidelity and the widest set of integration points, because they have a whole operating system to reach into: an EHLLAPI library that a twenty-year-old binary can load, a printer session that appears as a real device, a COM object another desktop application can drive. What that costs is per-machine. Something is packaged, installed, patched and version-matched on every desk, and the Windows-only ones decide what the desk has to be.
Server-delivered browser sessions — Z and I Emulator for Web, Inventu Viewer+, PowerTerm WebConnect, 3270Web — put nothing on the desk. One place to upgrade, one place to control who reaches which host, and a Chromebook or a tablet is as good a terminal as a laptop. The trade is that anything which had to touch the local machine has to be re-earned some other way, over an API rather than a DLL.
Open source — the x3270 family and 3270Web — means the thing can be
read, forked, audited and deployed without a purchase order. It is the
smaller half of this category by a distance. 3270Web builds directly on
s3270; see Acknowledgements.
Where 3270Web is different¶
Comparing against the category rather than against any one product, because these are axes rather than checkboxes:
| Axis | Where the category generally sits | 3270Web |
|---|---|---|
| Getting a terminal onto a desk | An install, or a server product plus a client entitlement per user | A URL |
| Automating a flow | A vendor macro language, or EHLLAPI against a presentation space | The recording made in the browser is the JSON an API replays — no second language in between, and it decides, repeats and remembers without becoming one |
| Serving somebody who does not know the application | Out of scope: the operator is expected to learn the green screen | Guided Business Tasks — named inputs, a named answer, no green screen |
| Finding out what an application actually does | Documentation, or a person with twenty years of it | Chaos exploration walks it and produces a screen mind-map, diffable between two hosts |
| Regression-testing a host application | Left to whatever test tooling the shop already has | Named screen snapshots, diffed row by row, over the API |
| Accessibility | Rarely stated in public documentation at all | A tested WCAG 2.1 AA statement, including where it falls short |
| AI | Increasingly offered, generally as the vendor's own service | Bring your own provider — six of them — plus an MCP server any agent can drive |
| Reading the source | Closed, with the x3270 family the long-standing exception | Open, on GitHub |
Where the field is ahead¶
The honest half, and the reason the next section exists. These are capabilities the established emulators have had for years and 3270Web does not:
- Printing to the operator's own printer. A 3287 printer LU is now bound and collected — see Printer sessions — but the job arrives in the browser as a file. An installed client can hand it to the print spooler on the desk it is installed on; a browser tab cannot, and no amount of work here changes that.
- Protocols beyond TN3270. 5250, the protocol AS/400 and IBM i hosts
drive their terminals with, and VT for everything else, usually ship in the
same box. 3270Web speaks TN3270 and TN3270E only — and so does
s3270underneath it, which carries no 5250 at all. Those hosts are still reachable, through a 3270 front end of their own rather than through anything 3270Web does; see AS/400 and IBM i hosts for the two conditions that come with it. - A loadable EHLLAPI library. The HLLAPI-shaped endpoint ports a screen-scraper by changing how it calls rather than what it does — but only if it can be rebuilt. A binary that links the DLL and has no surviving source still needs the DLL.
- DBCS and bidirectional language support. Arabic, Hebrew, and the double-byte character sets. Neither is a rendering tweak; both reach the code page handling and the field model.
- A scripting language with an editor and a debugger around it. A recording now decides, repeats and remembers — see Decisions, variables and loops — which closes the part of this gap that mattered most: a flow that reads a balance and takes a different path is now a recording rather than a person. What the established emulators still have is the rest of a language and the tooling around it: arithmetic, subroutines, an editor that knows the syntax, a debugger with breakpoints. Playback steps and shows every decision it makes, and that is not the same thing.
Category parity¶
Derived from the section above. None of these make 3270Web better at what it is already good at — they remove reasons an evaluation stops early.
- 3287 printer session — shipped: a printer LU bound beside the
terminal session, by name or as the display LU's associated printer, on
the same host and the same TLS terms. Each job the host prints arrives
as a file to download, from the panel or over the API.
pr3287does the protocol; what this adds is where a browser-delivered terminal is allowed to send paper. See Printer sessions - 5250, for AS/400 and IBM i — the same terminal, the same recording
and task machinery, pointed at the platform whose green screens are not
3270 ones. A larger job than it looks, and larger from here than from
most places:
s3270has no 5250 in it, so this is a second protocol engine rather than a switch on the existing one. 5250 has its own field model and its own AID set, and pretending otherwise is how an emulator ends up subtly wrong on both. Meanwhile these hosts are reachable through their own 3270 front end — model 2 only, with the 5250 function keys arriving as PF-key sequences - VT emulation — commonly in the same box as 3270, and the reason a shop can standardise on one client. Worth doing only if it does not compromise the 3270 path, which is what 3270Web is actually for
- DBCS and bidirectional language support — double-byte character sets, and right-to-left screens with the field-level orientation rules that go with them. Reaches the code page handling, the field model and the renderer, in that order
- A native EHLLAPI shim — a small DLL that presents the classic entry points and forwards them to the HLLAPI-shaped endpoint, for the binaries that cannot be rebuilt. The semantics are already implemented; what is missing is a library for them to load
- Decisions in a recording — shipped:
SetVariable,If/Else/EndIf,While/EndWhileandStopas ordinary steps in the same flat list, so a flow can read a balance off the screen and take a different path, or press a key until the host stops saying MORE. Every loop is bounded, a decision that cannot be made stops the run rather than guessing a branch, and a recording whose blocks do not close is refused when it is loaded rather than half-way through. See Decisions, variables and loops - Translating a macro's decisions, not just its steps — shipped: a
branch, a loop and a variable in a macro file become
If/Else/EndIf,While/EndWhileandSetVariablesteps, where the file says enough for the translation to be a translation. Which lines are inside a block is the file's own structure; the condition has to name a row, column and length, or a variable already read, compared against a literal. Everything else is reported — and a branch that did not translate takes its body with it, because the failure worth preventing is the one where theIfis dropped and the steps inside it start running every time. See Importing a macro file - Macro-file import — shipped: a macro file written against the session automation object model becomes a recording — its steps, and the branches, loops and variables the file says enough about — and every line that would not translate is reported with its number, its text and the reason. One click in the Automation menu, and on the API without a session so a directory of them converts in one pass. See Recordings and Playback
Recently shipped¶
Newest first. Every item here is live and documented.
-
A conformance suite that talks to the terminal — every test of how a screen is read used to be built from a captured
ReadBufferline, which answers "does this parse" and nothing else: the capture was written by whoever wrote the test, so it agrees with them by construction. A terminal-fidelity bug is exactly a disagreement between what the terminal says and what this code believes it says, and it survives that kind of test indefinitely — blink was compared against a value the attribute cannot hold for as long as there were tests for blink. There is now a scripted TN3270 host in the tree: a test writes a real 3270 data stream, a real terminal reads it, and the assertion is on the decoded screen. It also keeps every inbound record, so the other half of the conversation — which AID byte a key produces, which fields report as modified, where the host was told the cursor was — is checked for the first time. Three gaps came out of it on the first pass, each described below -
A first screen with nothing to type into — a report, a broadcast notice, a "system unavailable" message, a line-mode banner: display-only screens are ordinary, and one arriving first stopped the session coming up at all. The connection succeeded and the screen arrived; the terminal was then waiting for an entry field before it would answer anything, and fifteen seconds later the operator was told the host could not be reached. It could — it was already showing them something. Connections are now made by asking the terminal to make one rather than by naming the host on its command line, which also makes them faster and makes a genuine refusal say what went wrong
-
A field that wraps past the end of the display — the 3270 buffer is one address space that wraps, so when the first field attribute on a screen is not at the very first position, the positions in front of it belong to the last field: the one that runs off the bottom right and continues at the top left. Reading left to right cannot see that, and what happened instead was an invented protected field. That is right whenever the last field is protected, which is most of the time and is why it went unnoticed; when the last field is an entry field it showed the operator a region they could not type into, on a screen where the host was waiting for them to
-
Function keys spelled the other way — a PF or PA key arrives written several ways, because the tools and the people that produce one do not agree. This side already treated every spelling as a real AID key and then sent one of them to a terminal that has only "PF(3)", which answered "nonexistent or invalid name" — a strange thing to be told about F3. Every spelling now becomes the one the terminal answers to
-
The attributes that were decoded and then not shown — a terminal can get every byte of the data stream right and still show the operator the wrong screen, because between reading an attribute and drawing it there are two more places to lose it. A blinking field was read correctly and compared against a value the attribute cannot hold, so it decoded, travelled the whole way to the renderer, and named no style at all — steady text where the host had asked for attention. A reverse-video field was styled with a rule that cancelled itself, painting the text in the colour it was sitting on, so the line an application had picked out as the one that mattered rendered as a blank hole. Neither failed anywhere: no error, no log line, nothing to point at. Both are fixed, and both now have a test that fails on the old behaviour — including one that renders every attribute the decoder can produce and checks the stylesheet has heard of each style it names, because the gap between "the renderer says this" and "the stylesheet does that" is where a display attribute goes silently missing.
Alongside them, two attributes that were never read at all. A character
attribute — the Set Attribute order, which colours a run inside a field
rather than the field as a whole — was skipped over, so the four words an
application picked out in red came back in the colour of the line around
them. And the extended background colour, which the terminal reports and
which is a separate attribute from the foreground, was parsed and dropped.
Both now reach the screen. See
Terminal Capabilities
- The whole of an oversize display — a display can be configured larger
than its model, and this application offers the setting. What it then did
with the result was cut it back to the model's standard size: an operator
running 100x30 was shown 80x24 of it, with the setting that asked for the
rest still switched on and nothing saying where it had gone. The terminal
reports the size of the screen it is actually showing, and that is now the
size that gets drawn — bounded only against a figure no 3270 buffer address
can reach, which is a misread status line rather than a large display. See
Screen Size and Model Guide
- The byte the host actually sent — every screen this application serves has
been through its own parser first, which is the right arrangement for every
question except one: whether the parser is what went wrong. That is the
question a code page complaint asks, and it cannot be answered by the thing
being asked about — a pound sign showing as a hash looks identical whether the
host sent the wrong byte, the terminal read it against the wrong code page, or
this side mangled it afterwards, and the parsed screen is downstream of all
three. The terminal's buffer is now readable directly: a region by row, column
and length, as characters or as the host's own code points, and the field a
position falls in with the attribute byte that opens it. Two reads,
deliberately not wired into anything that serves a screen — this is a second
opinion, and a second opinion is only worth having when it comes from
somewhere other than the thing being checked. What did carry over is the
redaction: a password is still in the buffer whatever the display did with it,
and a read that went straight to the terminal would otherwise have been the
one way around the masking every other reader here applies. See
REST API.
- A host allowed to think for longer than fifteen seconds — the terminal's
own setting was to hold an AID key until the host gave the keyboard back, and
it held the session's one control pipe while it waited. Nothing else about
that session could happen meanwhile — including reading the screen to show
the operator that the host was busy — and the wait was bounded by a budget
whose expiry kills the terminal process. Measured against a host stopped at a
breakpoint, an Enter took thirty seconds and came back disconnected: a long
transaction did not fail, it ended the session. The key now returns as soon
as it is sent and the waiting is done in short steps with the pipe let go
between them, so the same measurement is twenty seconds, no error, session
intact — and twenty-nine screen reads got through while it waited, which is
what puts X SYSTEM in front of the operator instead of a page that has
stopped responding.
- What the operator typed, on the screen it was typed into — marking a
field changed and writing the changed fields to the host were two separate
holds of the session, with the browser's own work in between, and the screen
those marks live on is rebuilt from the host on every read. The live screen
stream reads every 700 ms, so a refresh landing in that gap handed back a
screen with nothing marked on it. It did not fail: the fields were simply not
written, and the AID key went to the host anyway. The operator watched their
typing disappear and the transaction go through without it. Reading the
screen, writing the input onto it and submitting it are now one step, taken
with the session held, and the only way to reach it is one that cannot be
split.
- The characters the code page was chosen for, on every platform — pinning
the terminal's character set through the environment works wherever the
platform has the one being asked for, and does nothing where it does not.
The terminal has its own switch for the same thing, needing no locale data at
all — but only on builds that have it, and naming an option an older build
does not know makes it refuse to start, which turns a cosmetic fix into no
terminal whatsoever. So the build is now asked what it takes, once, from its
own help output. Belt and braces, and the braces are the ones that work on a
Mac.
- The characters the code page was chosen for — a connection can name
cp285 or cp273 or cp880, and the pound signs, umlauts and Cyrillic letters
those code pages exist for did not arrive. Two separate reasons, both of them
invisible: the terminal describes the screen in whatever character set the
server was started with, a container image sets none, and "none" means ASCII,
so everything else was turned into a question mark before this program could
see it — and where a server did have a character set, one screen cell came
back as several bytes and was replaced with a null to keep the columns lined
up. The geometry was right and the word was gone. Going the other way had the
matching fault: text typed into a field was sent as the bytes of each
character rather than as the character, so an "é" landed on the screen as
"é" and pushed the rest of the field along a cell. The terminal is now
started with a character set rather than left to inherit one, a character is
one cell however many bytes it takes, and what is typed goes down as what was
typed. See Terminal Capabilities.
- A refusal is an answer — the terminal ends what it says about an action
with "ok" when it ran and "error" when it did not, and only the first was
ever being listened for. So a refusal was not an error here, it was a
silence: the reader was still waiting when the next action went down the
pipe, and answered that action's question with this one's output. When
nothing followed, it waited out the fifteen-second budget every action
shares — and running out of that budget kills the terminal process, so the
session went with it. None of the ways to trigger this were exotic. Typing
into a protected field is a refusal. So is a key the keyboard has locked out,
a PF number that does not exist, a reconnect to a port with nothing behind
it, and a transfer the host will not start. Each of those now comes back in
milliseconds, carrying the reason the terminal gave for it, with the session
still up — and a connection that is turned away says "Connection refused"
rather than "the screen was not ready", which was true and useless. The one
refusal deliberately not passed on is a host that has not released the
keyboard yet: the key was sent, the host has it, and that is what X SYSTEM
is for.
- A file transfer allowed to take as long as it takes — IND$FILE moved the
file over the same fifteen-second budget as a cursor move, and running out of
it killed the terminal process. So a transfer longer than fifteen seconds
lost the transfer and the session, and did so more reliably the more the
dataset was worth moving. It has its own budget now, sized for a file rather
than for a keystroke.
- The decisions in the shelf of macros, not just the steps — a recording
learned to decide, and the importer could still only hand over the straight
parts of a file, which left the branch — the reason the macro was written at
all — for a person. Now a branch, a loop and a variable come across as steps
where the file says enough for that to be a translation rather than a guess:
the block structure is the file's own, and the condition has to name a place
on the screen or a variable already read. What holds it together is one rule
going the other way — a branch whose condition did not translate takes its
body with it. Dropping the If and keeping its contents would turn steps
that ran on some days into steps that run on every day, against a live host,
under a report that said the branch needed a human and nothing about where
its statements went. The report now names the branch, the reason, and how
many statements went with it. See
Importing a macro file.
- A recording that can decide — the flow a shop actually has is not a
straight line: read the balance and take a different path under the limit,
press a key until the host stops saying MORE, skip the confirmation panel on
the days it is not drawn. Recordings now carry SetVariable, If/Else,
While and Stop as ordinary steps in the same flat list every reader of a
recording already walks, so nothing else had to learn a second shape. The
restraint is the design: a loop is always bounded, a condition that cannot be
evaluated ends the run instead of picking a branch, and a ${name} that
names nothing stops the run rather than typing those characters into a field
on a live host. Blocks that do not close are refused when the file is
loaded, before it has touched anything. See
Decisions, variables and loops.
- The shelf of macros that was keeping a shop where it is — a macro file
written for an installed emulator is read here and becomes a recording, and
the lines it will not take are named rather than dropped: this condition
nothing can read a position out of, that value computed from two others,
this text typed at a position the file cannot know. The refusals
are the feature. Guessing a coordinate would produce a flow that types an
account number into whatever field the host happened to leave the cursor in,
and that is discovered in production rather than in the report. The
translation and the report are on the API as well, needing no session,
because a shop with one macro has three hundred. See
Recordings and Playback.
- A question about the screen in front of you — "explain this screen" was
a starter chip on an empty chat, which is the one moment an operator is
least likely to need it; the screen worth explaining is the one that arrived
four transactions into a flow. It is now a click from the Terminal menu, the
chat composer or the command palette, at any point in a conversation. The
screen goes with the question rather than being read a round later, because
a host is free to redraw while the question is being asked and an answer
about the wrong screen is worse than none. See
AI Chat Mode.
- An assistant that knows what this build can do — the terminal grew past
its own tool surface. Snapshots, the display toggles, the connection's own
account of itself, the printer session and the task catalogue were on the
API and nowhere an assistant could reach, so one asked whether 3270Web could
compare a screen against the one a flow used to land on answered from what
it could see — a keyboard and an exploration engine. They are tools now,
declared once and offered to the chat panel and the MCP server alike, which
also gives the panel the saved tasks it never had. See
AI Chat Mode.
- Somewhere for the batch output to go — a 3287 printer LU bound beside
the terminal session, by name or as the associated printer of the display
LU the host bound, and always on the same host and TLS terms as the session
it belongs to. What the host prints arrives as a file to download rather
than as paper, which is the trade a browser makes; a job too large to keep
is named as truncated rather than quietly ending early. See
Printer sessions.
- A deployment's set-up as a file — the host presets and the recorded
tasks in one versioned document, so a second instance is configured by
importing rather than by retyping forty entries in the right order. It says
what it would change before it changes anything, and a file it cannot store
in full it does not store at all. See
The session manager.
- An accessibility claim with an audit behind it — thirteen surfaces
tested, four conformance failures fixed, and a statement that says where it
falls short rather than only where it does not. See
Accessibility.
- A door in the shape of the old one — an HLLAPI-shaped endpoint, so a
screen-scraper written against numbered functions and presentation-space
positions can be pointed at 3270Web without being rewritten. See
REST API.
- Touch — a bar of terminal keys within a thumb's reach on a tablet or a
phone, riding above the software keyboard rather than behind it, and a tap
on protected text that places the cursor there. Without an AID key a device
with no keyboard could read a screen and never end one. See
Keyboard and Controls.
- The terminal inside another application — a named allowlist of origins
that may frame 3270Web or call its API from a page, a chrome-less
?embed=1 rendering, and a postMessage channel for the page around the
frame. Documented end to end, including why HTTPS is not optional for it.
See Embedding 3270Web.
- Screen snapshots, display toggles and screen tracing — the screen frozen
under a name and diffed row by row, so a flow can be checked against the
screen it used to land on; the terminal's own display settings read and
written where they live; and every screen recorded as it is drawn,
including the ones replaced before anyone asked to see them. See
REST API.
- The connection's own account of itself — negotiated telnet options, TLS
state, terminal name and byte counts, none of which the screen shows, in a
Connection panel one click from the terminal and on the API for scripted
checks; and a graceful host disconnect on teardown rather than a killed
subprocess. See
Keyboard and Controls.
- A cursor that is not confined to the fields — it can rest on any cell of
the display, so screens driven by cursor position rather than field content
are operable; and auto-skip now follows the field-attribute rule instead of
approximating it. See Keyboard and Controls.
- Guided Business Tasks — record a screen flow once, and anyone can run
it from a form and read the answer without navigating a green screen.
Named inputs, named outputs, and a run that stops at the first divergence
rather than typing into a screen nobody expected. See
Guided Business Tasks.
- Choice of AI provider — GitHub Copilot, Claude, OpenAI, Google AI,
Ollama (local or cloud), or any OpenAI-compatible endpoint, selected from
the chat panel. Each provider keeps its own model and credentials. See
AI Providers.
- Customisable keyboard mapping — rebind by pressing the key, with JSON
export/import and a .KMP keymap-file importer that reports what it could
not map. See Keyboard and Controls.
- IND$FILE file transfer — send and receive, text or binary, with TSO
dataset-creation options and PDS member names.
- Concurrent sessions with tabs — up to six live host sessions in one
browser, fully independent.
- Server-side connection profiles — per-host TLS, certificate
verification, LU name, terminal model and code page.
- Screen tools — hotspots on the application's own key legends, find
over the character grid (so it matches typed values), screen history for
the last 50 screens, screen-accurate and rectangular block copy.
- Terminal fidelity — local cursor movement with no host round-trip, a
real OIA (X SYSTEM, X -f, insert indicator), numeric-field
enforcement with an operator-error lock, insert/overtype, and type-ahead.
- Focus mode and workspace modes — the terminal fills the display with
an auto-hiding menu rail; Business is the default surface and
Engineering is one click away.
- Chaos exploration hardening — saturation detection, structural screen
dedup, smarter value generation, automatic exit-key blocking, a Markdown
discovery report, and mind-map export/import. See
Chaos Mode.
- Host Compatibility Profiler and Chaos Mind-Map Compare — see
Host Compatibility Profiler and
Chaos Mind-Map Compare.
Guided Business Tasks¶
Complete: authoring from a recording, running from a form, the token-authenticated API, export/import, and conversion from a chaos run. See Guided Business Tasks.
- Authoring wizard — shipped: record a flow, confirm the derived inputs, repair the guard on any step against the screen it runs on, mark the answer by clicking or dragging on the final screen, and see what the server would read back before saving. A recorded password is marked as a secret and never written to the catalogue. See Guided Business Tasks
- Editing a saved task — shipped: Tasks → Edit reopens a task in the same wizard, so a mislabelled input or a region a character too short is a correction rather than a re-recording. See Guided Business Tasks
- Export / import task definitions — shipped:
GET /api/v1/tasksreturns exactly whatPOST /api/v1/tasksaccepts, so the catalogue moves between deployments and into version control with no separate format - Task API — shipped:
POST /api/v1/sessions/{id}/tasks/run, token-authenticated and synchronous, so a bot gets the answer in the response. See REST API - Chaos import — shipped:
GET /chaos/business/task-draftconverts a discoveredBusinessFunctioninto a task draft, deriving guards from the screen text the run captured. See Guided Business Tasks
Daily-use fidelity¶
Behaviours an experienced 3270 operator expects from the terminal itself. Tracked apart from features because they are not features — they are whether the thing behaves like a terminal. The rest of this list is shipping; see Terminal Capabilities.
- Strict auto-skip semantics — shipped: auto-skip now follows the field-attribute rule rather than approximating it as "the field is numeric". See Keyboard and Controls
- Cursor movement over protected areas — shipped: the cursor can rest on any cell of the display, which is what makes "position the cursor beside your choice" screens operable. See Keyboard and Controls
- Focus mode vs. a MAX-size keypad — shipped, and the call is that the terminal wins: focus mode exists to give the terminal the display, so the keyboard takes a share of it and the terminal takes the rest. Measuring first found the two were not merely fighting over the space — they were bidding for it, each sizing itself from what the other had just released, until both overflowed and the terminal's first rows were pushed above the top edge. See Keyboard and Controls
s3270 actions not yet surfaced¶
s3270 publishes about ninety actions. 3270Web drives roughly a third of them,
and the rest divide into three groups: a handful worth having, a larger set that
belongs to protocols this terminal does not speak, and a scripting family held
back on purpose. All three are below, because "not surfaced" and "not wanted"
are different answers and a roadmap that only lists the first is a to-do list
pretending to be a plan.
Wiring one up is usually a wrapper job, but "usually" is doing work in that
sentence: an action that occupies the control pipe while it waits, or that
writes a file, or that changes what the terminal will accept, is a design
decision before it is a wrapper. Each item below says which kind it is.
String(), Transfer(), PrintText(), Snap(), Set()/Toggle(),
ScreenTrace(), Query(), Ascii(), Ebcdic(), ReadBuffer() and
Disconnect() are already done.
-
Query— shipped:GET /api/v1/sessions/:id/queryreturns everything the terminal knows about the connection — negotiated telnet options, TLS state, terminal name, byte counts — none of which is on the screen. See REST API - Explicit
Disconnect— shipped: teardown closes the host session before the subprocess goes away, instead of killing it and leaving the TCP connection for a gateway to notice in its own time -
Snap()— shipped: the screen frozen under a name and compared row by row, against another snapshot or against the screen as it stands now. That is what makes a regression test against a green screen possible: the answer is which rows moved, not pass or fail. See REST API -
Toggle()/Set()— shipped: the display toggles this build actually has — monocase, crosshair, cursor blink, the underscore under input fields — read from and written to the terminal rather than mirrored here. A narrow allowlist, because the same action also reaches trace files and printer sessions -
ScreenTrace— shipped: every screen recorded as it is drawn, including the ones the host replaced before anyone asked to see them — the screens a poller can never find. BehindALLOW_SCREEN_TRACE, because it writes a file holding everything that crossed the display. See REST API -
Ascii()/Ebcdic()/ReadBuffer()— shipped: a region read by row, column and length, and the field a position falls in, both answered out of the terminal's own buffer rather than out of this side's parse of it.?encoding=ebcdicgives the host's code points, which is what a code page complaint needs — the byte the host sent, before anything here interpreted it. Cells inside a hidden field are masked on the way out, because reading the buffer directly must not be the one way around the redaction every other reader applies. See REST API - A host-details panel in the browser — shipped: Connection in the terminal header reads the same endpoint the API does, so the connection's own account of itself is one click away rather than API-only. See Keyboard and Controls
Worth having¶
-
SaveInput()/RestoreInput()— the host redraws the panel while somebody is half-way through filling it in, and everything typed is gone. Every operator in this category knows that feeling and most have learned to type the whole thing again rather than find out. These two hold what was entered across a redraw and put it back. A wrapper job, and the question that comes with it is whose decision the restore is — automatic is surprising when the host redrew because the input was wrong -
Trace()— the data stream, whereScreenTraceis the screens. They answer different questions: the screens say what the operator saw, the stream says what the host actually sent, and only the second one settles an argument about whether a field attribute arrived. Behind a switch and a server-chosen path, exactly as screen tracing is, because it writes a file holding everything that crossed the wire -
Wait()beyondUnlock—Wait(Output),Wait(InputField),Wait(Disconnect),Wait(3270Mode). Playback, chaos exploration and the live screen stream all wait by asking again on a timer; these are the terminal's own way of being told. Not a wrapper job: a wait occupies the one control pipe the session shares, so a keystroke arriving mid-wait has to queue behind it. Worth it only where the wait is bounded and short, and worth measuring before believing -
KeyboardDisable()— a session that can be watched and not typed into. Useful over somebody's shoulder, useful in a demonstration, and useful as the honest shape of a read-only share, which is currently a thing this terminal cannot offer without simply not giving out the URL - The host's alarm — the write control character that rings the bell is part of the 3270 data stream and part of how an application says "look at this". A browser tab has somewhere to put that; today it goes nowhere
-
Reconnect()— reconnect to the host just disconnected from, on the terms already negotiated. The session reconnects by re-issuing the originalConnect(), which is the same thing until a deployment's target is a name resolving to more than one address
Belonging to protocols this terminal does not speak¶
Listed so nobody has to check twice. Interrupt(), AnsiText(), NvtText(),
Expect(), PageUp()/PageDown() and the scrollback around them are NVT-side:
they become interesting only if VT emulation does, and are
otherwise dead surface. Flip(), CircumNot() and TemporaryComposeMap()
belong to bidirectional and composed input, which is the
DBCS and bidi item and reaches the field model long before
it reaches an action wrapper.
Held deliberately¶
-
Source()/Macro()/Script()/Prompt()/Execute()— native s3270 scripting. Held rather than pending:Source()reads a file of actions,Script()andExecute()start a process, and a macro would run on the same control pipe the session depends on. What they are wanted for — running a recorded sequence against a host — is already Guided Business Tasks and workflow replay, over validated steps rather than raw actions. The open question is whether any remaining case justifies the surface -
Cookie()— authentication for s3270's own script interface. It matters only if that interface is ever exposed, and exposing it would mean a second door into the session with its own authorisation model beside the one every other surface here already shares. The reason it is on this list is to record that the answer is currently no
Enterprise deployment¶
These gate a production rollout rather than daily usability. A pilot can proceed without them; procurement cannot.
- Accounts and per-user separation — shipped:
AUTH_MODE=localgives a sign-in page, an account each with roles, and one person's terminal sessions, chaos runs, tasks and saved work kept from another's — administrators included. API tokens belong to accounts and reach only what their owner reaches. See Running a shared instance - Attributable audit logging — shipped: who signed in, who opened a
session against which host, who changed an account or a setting, and
every refusal — in a file of its own, admin-readable at
/admin/audit, with no switch to turn it off. See The audit trail - OIDC single sign-on — shipped:
AUTH_MODE=oidcsigns people in through the directory an organisation already runs, provisioning an account on first use and mapping roles from a group claim. Local accounts keep working alongside it, deliberately: an instance whose only door depends on a service it does not run can be locked out of itself by somebody else's outage. See Single sign-on - SAML — the same job for organisations whose directory does not speak OIDC. A different protocol rather than a different identity model: the account an assertion resolves to, and everything downstream of it, is what OIDC sign-in already builds
- WCAG 2.1 AA conformance statement — shipped: an audit across thirteen surfaces, the failures it found fixed, and a statement that names what conforms, what does not, and which two apparent failures are deliberate. See Accessibility
- A session manager — shipped: an administrator assigns published host profiles to groups, roles or named accounts, and an operator whose account reaches one mainframe is connected straight to it while one who reaches several lands on a real 3270 selection screen. Branded, paged, and driven by the terminal's own keys. See The session manager
- Distributable task and profile libraries — shipped: the recorded tasks and the host presets as one versioned document, downloaded from one deployment and imported into the next. The import says what it would do before it does it, reports every entry, and refuses a file it cannot store in full rather than storing half — because the state a library exists to prevent is two instances quietly disagreeing about which mainframe a name points at. Audiences naming individual accounts are left out, since those accounts exist only where the file came from. See The session manager
Web-native and integration¶
Complete. The terminal can be framed by a named origin, driven from the page around it, called cross-origin as an API, used with a finger, and reached by a screen-scraper that still speaks HLLAPI.
- Embed-in-iframe / SPA integration story — shipped:
EMBED_ORIGINSnames the origins that may frame the terminal or call the API from a page,?embed=1renders it without chrome, and a postMessage channel lets the surrounding page read the screen and press keys. See Embedding 3270Web - Mobile / touch UI — shipped: a thumb-reachable bar of AID keys that rides above the software keyboard, tap-to-place-cursor on protected text, and a screen that scrolls and zooms rather than reflowing. See Keyboard and Controls
- HLLAPI-shape scripting endpoint — shipped: numbered functions,
one-based linear positions and return codes, so an existing
screen-scraper is ported by changing how it calls rather than what it
does.
"SMITH@E"still means what it always meant. See REST API
AI-assisted use¶
Complete, and kept here rather than deleted: what an AI section promises is the part a reader is most entitled to check, and a list of what was actually built is the only honest way to let them.
What is live: a chat panel beside the terminal that drives the session
through a tool surface of about forty calls — read the screen, write a
field, press an AID key, wait for the host, connect somewhere, run and steer a
chaos exploration, annotate what it learns, catalogue a business function,
generate a workflow from one, run a saved task and report its answer, freeze a
screen and say which rows moved since, read what the connection negotiated,
change a display toggle, collect what the host printed. Six AI providers to choose between, each with
its own credentials. Procedures kept as
skills and instructions in files, so an installation can add its
own without editing a prompt. An MCP server over stdio and HTTP with
safety tiers and a host allowlist, offering every Guided Business Task as a
tool of its own. Per-call approval, and an auto mode that still stops at
ask_user. And everything read from a host wrapped as untrusted data, because
a screen can be made to read like an instruction and the assistant is told,
in the prompt, not to take one from it.
See AI Chat Mode, AI Providers, Skills and Extensions and MCP Server.
What this section once listed as outstanding, and where each of it landed:
- Natural-language → keystrokes — shipped: this is what the tool
surface is. "Fill in the account number and press Enter" resolves to
write_fieldandsend_keyagainst the screen the assistant just read, with the call shown before it runs unless auto mode is on - AI-proposed task authoring — shipped by a different route than the one imagined here: a chaos run's discovered business function converts into a task draft, guards derived from the screen text the run captured, for a human to confirm. Nothing about Guided Business Tasks requires AI — the authoring wizard works from a plain recording — which is the difference between a differentiator and a dependency
- "Explain this screen" from the terminal, at any point — shipped: one click from the Terminal menu, from the composer, or from the command palette, at any point in a conversation rather than only on an empty one. The screen is captured when the question is asked and carried with it, so the answer is about the screen that prompted the question and not whichever one the host drew while it was being asked. See AI Chat Mode
- An assistant that knows what this build can do — shipped: the capabilities that were on the API and nowhere a model could reach are tools now. Snapshots — take, list, diff, delete — so a flow can be checked against the screen it used to land on; the display toggles; the connection's own account of itself; the printer session and the jobs it has collected; and the Guided Business Task catalogue, with a run that waits and returns the answer rather than the step list. Declared once and offered on both surfaces, the chat panel and the MCP server, and named in the system prompt — a tool a model has to guess at is a capability it will tell the user this build does not have. See AI Chat Mode
Where the leverage is¶
Three areas where 3270Web can lead rather than match:
- Guided Business Tasks. They change who can use the product. Everything else here makes a terminal better for people who already use terminals; this serves people who only know the business question.
- Accessibility. A documented WCAG and screen-reader story is rare in this category, and most of the work is already done — deriving each field's label from the screen's own text is the hard part, and it exists.
- Public REST API plus workflow JSON. Paired, they make 3270Web straightforward to adopt for RPA and CI: a flow recorded by hand is the same document an automated job replays, with no separate scripting language in between.