This is a full reference on those
 functions and fields exposed by the
 kernel to processes and libraries.

Firstly, it is important to note that
 a process runs within a coroutine.

This allows a highly "traditional"
 form of mixing async and synchronous
 code with event-loop nesting and
 such designs. If this is not to your
 taste then you can just use one, not
 nested event loop.

As it runs in a coroutine, events are
 received via coroutine.yield() -
 sandboxers beware! You may have to
 use coroutine.running() in order to
 successfully hide the implementation
 details of your sandbox (also events
 and potentially accesses headed in
 its direction...)

NOTE regarding security of this!

For efficiency, APIs are generally
 used "directly". This allows read
 access to all events, including any
 security responses.

The assumption made here is that if
 you're communicating with an app you
 don't trust, you will wrap access to
 it in a coroutine shell, and perform
 ensureType usage on everything that
 it spews out.

In particular, this is a good way to
 isolate yourself from any effects,
 including timeout, of a function you
 know to be environment-sandboxed:

coroutine.resume(coroutine.create(
 functionIDontTrust))

An example KittenOS NEO program,
 solely using kernel APIs,
 that you will likely have to kill:

neo.scheduleTimer(os.uptime() + 1)
while true do
 local ev = coroutine.yield()
 if ev == "k.timer" then
  neo.emergency("Hello...")
  neo.scheduleTimer(os.uptime() + 1)
 end
end

This will say "Hello..." via the
 neo.emergency mechanism once every
 second, independently of anything
 else on the system.

While this is obviously not a sane
 sys-init for actual use, if you have
 a disk that you can copy the kernel
 to and a copy of this, it might make
 a fun experiment.

The way to exit the program is to
 return from your process's main
 function.

The first field to note is:

_VERSION: _VERSION from the host.

The following are just wrapMeta'd
 host libraries (*: altered):

math, table, string, unicode*,
 coroutine, os*, debug, utf8, bit32

unicode is extended with:
 safeTextFormat(s, p):
  Takes a string s, and a position p,
   (the position is optional, and is
     assumed to be 1 otherwise)
   and returns a space-padded string,
    with a space after each wide char
    to make unicode.len & co. act in
    screen units, along with the
    position translated.
 undoSafeTextFormat(s):
  Takes a string in padded-widechar
   format, and gets rid of the pad.
  Note that if padding is *missing*,
   wide characters become spaces.
  This leaves a string that's usually
   safe to pass to a GPU without any
   odd graphical glitches.

The KittenOS NEO kernel also reserves
 the ability to take advantage of any
 full de-UTF16'd support for Unicode
 available on the system, but will
 not include such support as a shim
 for memory usage reasons.

Programs that thus try to work around
 this problem should delegate this
 task to a library, in a separate
 package, which can then be updated
 as-needed if and when the issue is
 resolved.

os is extended with:
 totalMemory = computer.totalMemory,
 freeMemory = computer.freeMemory,
 energy = computer.energy,
 maxEnergy = computer.maxEnergy,
 uptime = computer.uptime,
 address = computer.address

The following are just host functions
 (*: wrapped for security - these
  functions detect metatable abuse):

 assert, ipairs, load, next*,
 pairs, pcall, xpcall, select,
 type, error, tonumber, tostring,
 setmetatable, getmetatable*,
 rawset*, rawget, rawlen, rawequal

(NOTE: Before you consider that load
 has no checks: The policy regarding
 load is taken from the host system.
 Which means bytecode loading is
  almost certainly off. If it's not
  off, then this is the user's fault,
  as doing so is marked as a security
  risk for very obvious reasons.
 As for trying to use the environment
  to bypass a metatable, I tested.
 Metatables do apply to environments,
  including global creation.
 There is no way to win.)

"require" and "neo" are the parts of
 the environment where a NEO-specific
 nature presents itself.

require takes a string, and returns
 the value returned by the library at
 "libs/" .. str .. ".lua" on the
 primary disk.
 Since R2, the value is automatically
  wrapMeta'd, just in case.
 Before R2, libraries did this on
  their own, but this caused NEO-only
  code to crop up in libraries that
  did not need NEO-only code.

The library name must be a valid path
 component, and the library path must
 also be valid - see
 ensurePathComponent, ensurePath for
 more info.

The "neo" table is where most of the
 NEO-specificness is hiding, which is
 probably shown by its name.

It is also where libraries differ to
 processes, as libraries get a subset
 of the table.

For libraries, it contains:
 emergency: Equals ocemu.log, if
  available on the system. Else, NOP.
 readBufSize: The readBufSize kernel
  configuration value. Default: 2048.
  Adjusting this in the kernel allows
   adjusting how much the system will
   read at any given time, which can
   have non-obvious memory usage
   effects.
  Do note, following this limit is
   not a requirement and is not
   enforced - it's not a security
   matter, just optimization/memory.
 wrapMeta(v): A function that takes a
  value, and wraps it in such a way
  as to be immutable, returning the
   wrapped value.
  This is the first line of defense
   against memory use - by using this
   to protect a table, the result can
   be shared between untrusted code.
 listProcs(): A function that returns
  an ipairs-friendly process list.
  Values are:
  {pid, pkg, cpuUsageInSeconds}
 listApps(): Returns an
  ipairs-friendly list of
  applications on the system, like:
  {"app-test", "svc-liliput"}
 listLibs(): Returns an
  ipairs-friendly list of libraries
  on the system, such as:
  {"fmttext",
   "braille"}
 usAccessExists(s):
  Returns true if the specified
   access has been registered from
   userspace using the related "r."
   access.
 totalIdleTime(): Returns the current
  kernel idle time total, useful for
  measuring current CPU usage, and in
  turn comparing to application CPU
  time to get various statistics.
 ensurePath(s, root):
  Attempts to verify the
  safety of a path, and errors if any
  aspect seems incorrect.
  The root must be a prefix to the
   path, and the path must follow a
   strict standardized form that is
   guaranteed to always be supported
   and handled in the same way on any
   OC system.
  Essentially, "//" must not occur,
   and all "[^/]+" matches must be
   valid path components.
 ensurePathComponent(s):
  Ensures that a string is a safe
   filename via a character list and
   some special filename checks.
  UTF-8 characters are just flat out
   disallowed until someone can give
   me proof they won't blow up
   something somewhere.
  (This restriction is Windows's
   fault - I can't trust the encoding
   mess to not find some new and
   imaginative way of breaking
   filenames, so I'd rather that they
   get avoided until someone can try
   actually using them.)
  This does NOT ACCOUNT for *all* the
   Windows total nonsense (aux, com1)
   because if OC doesn't cover up
   that then you're kinda doomed.
 ensureType(v, ts):
  Checks that a value is of a given
   type, and errors otherwise. If the
   type is "table", it also errors if
   a metatable exists.

The additional things available to
 processes are those things that
 require a process to use:

 pid: A field that specifies the
  process ID of this process.
  Harmless, but not entirely useful.
 pkg: A field that specifies the
  package name of this process.
  Useful if you're worried about
   your app getting renamed.
 dead: Actually a field, that isn't
  set at first, but is set later to
  indicate deadness. Useful if your
  process does anything that might
  lead to functions being called in
  the afterlife, such as providing an
  API.
 executeAsync: Function that takes
  an app name (aka: pkg), and a
  set of arguments to give it.
  NOTE: sys- apps cannot be started
   from non sys- apps no matter how
   hard you try, without k.root
   alterations to runProgramPolicy.
  Your process pkg and ID is
   prepended to the arguments.
  NOTE: This uses the result, err
   return format, except for security
   errors in which case it uses a
   full error, because you might just
   ignore the return value.
  A successful result is the PID.
 executeExt: Like executeAsync, but
  firstly, synchronous, and secondly,
  with an extra first parameter that
  contains a function to call on
  events encountered during the time.
  As for the return values, it tries
   to emulate os.execute, so it
   returns -1 & reason on load error,
   and 0 & death-reason otherwise.
 execute: executeExt, but with the
  first parameter set to a blank
  function.
 requestAccessAsync: A function that
  takes an access ID (aka 'perm') as
  a string (see kn-perms for info),
  and starts a security request that
  is responded to with a
  k.securityresponse such as:
  "k.securityresponse", perm, obj
 requestAccess(perm[, handler]):
  Runs requestAccessAsync, then sends
  events to handler (if any) while
  waiting for the response.
  sys-icecap is responsible for any
   automatic starting of services
   that may occur.
 requireAccess(perm, reason): requestAccess, but
  (perm, reason) - the reason is used
   in an error if the access cannot
   be gained.
 scheduleTimer: Given an os.uptime
  value, creates a timer and returns
  a completely meaningless table that
  is never touched by the kernel
  directly, called the "tag".
  The resulting event:
  "k.timer", tag, time
  These events are ONLY EVER sent as
   a consequence of this function,
   and this can be relied on safely.
  NOTE: Setting timers too far in the
   future has effects on system
   stability. So does using memory,
   and there's no way for me to stop
   that, either. So long as the timer
   is reached, alive or dead, things
   will work, but spamming timers has
   the consequence of memory use,
   and timers stick around after the
   process that owns them is dead.

The list of events, tacked on at the
 end here:

k.procnew(pkg, pid, ppkg, ppid):
 New process creation, with parent
  information (for seat tracking)
 This is not given to the process
  being created, as all of this gets
  given to it anyway on main function
  start.

k.procdie(pkg, pid, reason, cpuTime):
 Process death.

k.registration(uid):
 Registration of an access.

k.deregistration(uid):
 Deregistration of an access.

k.securityresponse(perm, obj):
 Response to a security request made
  with neo.requestAccess or such.

k.timer(tag, time):
 A timer. Includes the planned uptime
  for comparison.

h.*(...): 
 Hardware signals, by type, such
  as "h.key_up"

h._kosneo_syslog("kernel", ...):
 System log entry. This is actually
  generated by the kernel as part of
  the emergency function processing.
 Note the "kernel" component address.
 The other parameters are the values
  given to the emergency function.
 You should tostring all of these.

With that, I hope I have documented
 the kernel's interface to programs.

-- This is released into
 the public domain.
-- No warranty is provided,
 implied or otherwise.