This document explains the kernel architecture, the boot lifecycle, how to create programs, jobs, libraries, and subsystems, how the message system works, database persistence, and how to develop and run locally.
Contents:
- Overview and Conventions
- Kernel Boot and Lifecycle
- Core (System) and Managers
- Jobs and Subsystems
- Libraries and Program/Object Catalog
- Message System (Message Queue)
- Persistence (DatabaseManager / SQLite WASM / IndexedDB)
- Security and Authority (AuthorityManager)
- Base Program class and Terminal APIs
- Creating a new Program (step by step)
- System Auditing (AUDITJRNP, DSPAUDLOG, DSPAUDMON)
- How to run in development
- Tips and Troubleshooting
WebOS/400 is a web OS inspired by IBM i/AS/400 with a 100% object‑oriented architecture. Every system element (programs, jobs, subsystems, libraries) is an object derived from SystemObject.
Key directories:
src/kernel/core/: kernel core and managers (jobs, subsystems, libraries, messages, authority, DB, etc.).src/apps/system/: system programs (e.g., SIGNON, MAIN, SYSSTATUS, commands and utilities).src/ui/: UI (Terminal, SystemUI, styles, etc.).
Conventions and IDs:
- Objects use IDs in the form
LIB/NAME.TYPE(seeSystemObject). - Qualified program name:
LIB/PGM; unqualified:PGMresolved via job’s current library and library list. - System message queues:
QSYSOPR,QSYSMSG,QHIST.
File: src/kernel/bootstrap.js
Boot flow:
- Instantiate
Systemand callsystem.initialize(). - Expose
window.webOS.system = systemfor console inspection. - Create and initialize
SystemUIandTerminal; attach Terminal to#terminal-container. - Start the interactive subsystem
QINTER. - Create the initial user job:
QSECOFR/QINTER/SIGNON. - Run the
SIGNONprogram on the initial job throughProgramManager.
Boot failures display an error screen with F3/F12 hints.
File: src/kernel/core/System.js
Kernel components:
MessageQueue: message queues and listeners.JobManager: create/end/list jobs.SubsystemManager: create and control subsystems.LibraryManager: libraries and objects.AuthorityManager: users, groups, authority checks.ProgramManager: program registration, cataloging, and execution.DatabaseManager: SQLite persistence (sql.js/WASM) in IndexedDB.
During System.initialize():
- Initializes DB, MQ, and all managers.
- Ensures system libraries and subsystems (QSYS, QGPL, QTEMP, etc.; QINTER, QBATCH, QCMN).
- Sends a “system initialized” message to
QSYSOPR. - Starts
QBATCHand launches the audit jobAUDITJRNPin the background (non‑blocking).
System status:
getSystemStatus()exposes state, uptime, simulated load, job/subsystem counters, and memory.
Files: src/kernel/core/JobManager.js, src/kernel/core/Job.js, src/kernel/core/SubsystemManager.js, src/kernel/core/Subsystem.js
Jobs:
- ID format:
NNNNNN/USER/JOBNAME(e.g.,000001/QSECOFR/SIGNON). - Each job has its own message queue (
JOB_<id>), status, priority, and call stack. - Libraries:
currentLibraryandlibraryListwith helpers (setCurrentLibrary,setLibraryList,addToLibraryList,getLibraryList). Defaults:currentLibrary='QGPL',libraryList=['QTEMP','QGPL','QSYS']. - Job start/end events are sent to
QSYSMSG(for auditing).
Subsystems:
- Config:
description,maxJobs,autoStart,priority. - Each subsystem has a
SBS_<name>queue and a state (INACTIVE/ACTIVE). SubsystemManagerhandles create/start/stop;System.initialize()createsQINTER,QBATCH,QCMN(autoStart=true).
Files: src/kernel/core/LibraryManager.js, src/kernel/core/Library.js, src/kernel/core/ProgramManager.js
LibraryManagerloads/creates libraries and persists them in DB (libraries).- Each
Librarykeeps an object map (addObject,getObject,listObjects). ProgramManagerregisters in‑memory programs and catalogs them in DB (programs).
Program resolution in ProgramManager.runProgram():
- Accepts
LIB/PGM(qualified) orPGM(unqualified). - For unqualified names: searches the job’s current library and *LIBL (see
Jobhelpers). - Verifies the DB catalog; requires the program to be loaded in
ProgramManagerand cataloged. - Performs execution authority checks via
AuthorityManager.
Registration and cataloging:
- System programs are imported and registered in
registerSystemPrograms(). registerProgram(name, programClass, library)enables dynamic registration (adds to a library and catalogs in DB, persisted).
File: src/kernel/core/MessageQueue.js
- Default queues:
QSYSOPR,QSYSMSG,QHIST(created at init). sendMessage(queue, msg): assignsid,timestamp, enqueues, logs to history, notifies listeners.receiveMessage(queue, timeout): single‑consumer FIFO.addListener(queue, fn): every listener receives a broadcast fanout of each message.- Additional queues are created on demand.
Usage patterns:
- Jobs and subsystems emit events to
QSYSMSG(e.g.,JOB_STARTED,SUBSYSTEM_STOPPED). - Programs may consume/produce messages on their own or system queues.
File: src/kernel/core/DatabaseManager.js
- Uses
sql.js(WASM) loaded via CDN and persists the DB binary in IndexedDB. - DB name:
webos400(object storefiles), file key:webos400.db. - Migrations create tables:
users,libraries,files,members,records,programs,audit_log. - Indexes: unique
idx_audit_log_event_idguarantees event de‑duplication. - Helpers:
execute,query,queryOne,persist.
Note: for existing DBs, light migrations are applied during initialization to ensure new tables and indexes.
File: src/kernel/core/AuthorityManager.js
- Loads and persists users in SQLite (keeps an in‑memory cache).
- Ensures
QSECOFRuser on init. signOn(user, password),signOff(),getCurrentUser().checkAuthority(user, objectId, authority): validates*EXECUTE/*READ/*CHANGE/*ALLconsidering user, groups, and special authorities (e.g.,*ALLOBJ).ProgramManager.runProgram()usescheckAuthorityto validate execution authority.
File: src/kernel/core/Program.js
Lifecycle:
run(job, terminal, parameters): callsinitialize()thenexecute(); catches errors and callshandleError(); setsreturnCode.- Subclasses implement
async execute().
Kernel APIs inside a Program:
- Messages:
sendMessage(queue, msg),receiveMessage(queue, timeout). - Jobs:
createJob(user, subsystem, jobName). - Auth/User:
checkAuthority(),getCurrentUser(). - System:
getSystemStatus().
Terminal APIs exposed via Program:
writeToTerminal(row, col, text, attr?, color?).clearTerminal().setCursor(row, col).createInputField(row, col, length, name, value?).waitForInput()(orterminal.waitForSubmit()when available).- Default error handling:
handleError(error)writes at the last line with highlight.
Note: the Terminal interface is used indirectly by Program (see Program delegating to terminal.writeAt, clearScreen, etc.).
- Create the program file exporting a
defaultclass extendingProgram.
Example (simplified):
// src/apps/system/HELLOWLD.js import { Program } from '../../kernel/core/Program.js'; export default class HELLOWLD extends Program { constructor(system) { super('HELLOWLD', 'QGPL', system); this.description = 'Sample Hello World'; } async execute() { this.clearTerminal(); this.writeToTerminal(2, 2, 'Hello, WebOS/400!'); this.setCursor(24, 2); await this.waitForInput(); // waits for Enter/Fxx depending on Terminal support } }- Register the program in
ProgramManager.
Option A — Dynamic registration at runtime:
// Somewhere after boot (e.g., in an installer program or console) const { system } = window.webOS; const { default: HELLOWLD } = await import('./src/apps/system/HELLOWLD.js'); await system.programManager.registerProgram('HELLOWLD', HELLOWLD, 'QGPL');Option B — Static registration: add the import in registerSystemPrograms() inside ProgramManager.
- Follow the pattern for
SIGNON,MAIN,SYSSTATUS, etc. - After registration, the program is added to the library and cataloged in
programs(SQLite) automatically.
- Running the program
- Use
ProgramManager.runProgram(name, job, terminal, parameters?). - Typically a menu program invokes others passing the active
jobandterminal. - For console/dev usage: create a job in
QINTERand invoke from a caller program that owns the terminal.
*CURLIB/*LIBL resolution:
- Calling
runProgram('HELLOWLD', ...)without qualification resolves via the job’s current library and library list. - You can change
currentLibraryandlibraryListon theJobas needed (e.g.,job.addToLibraryList('MYLIB')).
Authority:
ProgramManagervalidates*EXECUTEfor the current user.QSECOFRhas full authority by default.
Relevant programs: AUDITJRNP, DSPAUDLOG, DSPAUDMON (in src/apps/system/).
AUDITJRNP: batch job started during boot (inSystem.initialize()), listens toQSYSMSGevents and persists toaudit_log. De‑duplication byevent_id(unique index + in‑memory processed set).DSPAUDLOG: viewer/searcher for persisted audit log (SQLite).DSPAUDMON: real‑time monitor, listening to new queue messages (MQ listener fanout) and displaying live.
MQ semantics applied to auditing:
- Listeners receive a broadcast fanout of every message on a queue.
receiveMessage()delivers each message to a single consumer (FIFO).
Prerequisite: Python 3 available on PATH.
- Install dependencies: there are no NPM deps; the project uses
sql.jsvia CDN. - Start a local HTTP server:
npm run start # or npm run dev # or python3 -m http.server 8080- Open
http://localhost:8080and wait for the SIGNON screen.
At runtime:
- The system object is accessible at
window.webOS.system(useful for console tests).
Persistence:
- The SQLite DB is saved in the browser’s IndexedDB under key
webos400.db. To reset, clear site data in DevTools (Application -> Storage -> Clear site data).
-
Program not found
- Ensure it is registered in
ProgramManagerand cataloged in the DB. - For unqualified calls, confirm it’s in the job’s *LIBL.
- Ensure it is registered in
-
Authority error when running a program
- Ensure the current user has
*EXECUTEon the program object (AuthorityManager). QSECOFRhas full authority.
- Ensure the current user has
-
Messages not reaching the listener
- Confirm
addListener(queue, fn)on the correct queue and that messages are sent withsendMessage.
- Confirm
-
DB “doesn’t persist”
- After changes via
DatabaseManager.execute, callpersist()when needed (kernel managers already do at critical points).
- After changes via
-
Terminal/UI
- Programs output via
writeToTerminaland often wait withwaitForInput(). The Terminal UI auto‑fits the container and uses an 80x24 fixed‑cell grid.
- Programs output via
- Boot:
src/kernel/bootstrap.js - Kernel:
src/kernel/core/System.js - Programs:
src/kernel/core/Program.js,src/kernel/core/ProgramManager.js - Jobs:
src/kernel/core/Job.js,src/kernel/core/JobManager.js - Subsystems:
src/kernel/core/Subsystem.js,src/kernel/core/SubsystemManager.js - Libraries:
src/kernel/core/Library.js,src/kernel/core/LibraryManager.js - Messages:
src/kernel/core/MessageQueue.js - Authority:
src/kernel/core/AuthorityManager.js - DB:
src/kernel/core/DatabaseManager.js - UI:
src/ui/components/Terminal.js,src/ui/SystemUI.js