gGodspeed CLI

What you can make

GodspeedOS runs four kinds of program, and godspeed new makes every one, plus libraries for them to share. Each kind is a different answer to one question: whose life does the program live? Pick the kind, and the template is the smallest program of it that works.

Service

The system's. Started at boot, restarted if it dies.

Utility

Its own. Runs when typed, ends with a status, pipes.

App

The operator's. Has the screen and keyboard while it runs.

Driver

Its device's. Given one device, by what the bus says it is.

Library

Nobody's. Built into what uses it, tested on your workstation.

What every kind shares

  1. Make it, and check it

    $ godspeed new <kind> <name> --publisher <you>
    $ cd <name>
    $ godspeed check            # the project, its toolchain, and its contract against the OS's schema
    $ godspeed build --all      # one ELF for each of x86_64, aarch64, armv7, riscv64

    Every template is written on the public standard library, gs, and nothing below it. CI makes, checks and builds every kind for all four architectures against the GodspeedOS release it names, so a template that does not build is a bug in this CLI.

  2. Package and publish it

    $ godspeed package          # every file, with its size and SHA-256, before anything leaves
    $ godspeed publish          # signed, uploaded, installable as you/<name>

    No network on the machine? godspeed package --local writes one .gsp file, signed with your key, that a machine installs once its operator trusts that key. Publishing has the one-time setup.

  3. Install it, on a Godspeed machine

    gsh> godspeed fetch <you>/<name>
    gsh> godspeed install <you>/<name>

    fetch downloads it and checks every signature; install starts only a package already fetched. Installing asks the operator for what the contract requests, by name, and grants nothing else. The contract asks; the machine decides.

Service works

A program the system keeps running: the supervisor starts it at every boot and restarts it if it dies. The shape of every server, logger and background job.

$ godspeed new service clock
#[no_mangle]
pub extern "C" fn service_main(ctx: ServiceContext) -> ! {
    ctx.log("clock: started");
    gs::ipc::park(&ctx)
}

Utility works

A program that does one job and ends, like a built-in command: typed at gsh> by its name, given its arguments, its output shown or piped, its status said.

$ godspeed new utility greet
let mut buf = [0u8; gs::program::ARGS_MAX];
let args = gs::program::args(&ctx, &mut buf);
let mut out = gs::program::Output::new(&ctx);
let _ = writeln!(out, "hello, {}", if args.is_empty() { "world" } else { args });
out.finish(0)
gsh> greet Bankole
hello, Bankole
gsh> greet Bankole | count
1 line, 2 words, 15 bytes

App works

A program the operator uses: it has the screen and the keyboard while it runs, and gives them back when it ends - even if it crashes.

$ godspeed new app notes
let app = gs::app::App::open(&ctx);
app.println("This screen is notes' until a key is pressed.");
let _key = app.wait_key();
app.close(0)

Driver works

A program that drives one device. Its contract names the device by what the bus says it is - a PCI class, or a USB vendor and product - never an address, and the machine finds which device that is.

$ godspeed new driver sensor
[capabilities]
hw_pci_class = "00ff00"   # QEMU's teaching device, `edu`
hw_pci_bar   = 0          # its registers are in BAR 0
hw_pci_irq   = true       # its interrupt: the OS picks the vector
hw_dma       = "8KiB"     # a DMA arena, memory the device reads and writes itself
// Shortened: the template says which grant is missing where this writes `?`.
let regs = gs::driver::registers(&ctx)?;     // the register window
let irq = Irq::granted(&ctx);                 // the interrupt
let mut layout = gs::driver::arena(&ctx)?.layout();
let out = layout.take("out", 64, 64)?;        // a named part of the DMA arena

regs.write32(STATUS, RAISE_ON_FACTORIAL);
regs.write32(FACTORIAL, 5);
match irq.wait(&ctx, Budget::ms(1000)) {      // bounded by time, never by a count
    Woke::Interrupt => { /* clear it, then */ irq.rearm(&ctx) }
    _ => ctx.log("sensor: the device did not answer"),
}

Library works

Reusable no_std Rust for the other kinds. Never installed: it is built into what uses it, so it requires no packages. Its tests run on your workstation.

$ godspeed new library parser
$ godspeed test

Which kind?

If it shouldMake a
keep running, with or without anyone watchingservice
do one job when typed, and endutility
take over the screen while someone uses itapp
talk to a piece of hardwaredriver
be code the others sharelibrary