kitengi programs are stored as plain text .kti files. The editor lets you copy, paste, and load them at any time.
The editor automatically saves your programs in your browser's local storage as you work. Your programs are available the next time you open the app in the same browser.
Click Copy source in the toolbar to copy the current program's .kti text to the clipboard. You can then paste it into any text editor, a GitHub Gist, a Slack message, or anywhere else.
Click Load from text in the toolbar. Paste a .kti program into the text area and click Load. The program is parsed and displayed on the canvas. If there are any syntax errors they are shown inline.
You can also drag a .kti file directly onto the canvas or use the Load from file option to open a file picker.
The kitengi desktop app (kitengi-electron) provides the same visual editor as the web app, packaged as a native Electron application. The desktop app includes a built-in bridge, giving programs direct access to filesystem and networking nodes (file-read, file-write, dir-read, dir-create, tcp-listen, etc.) without any additional setup.
This makes the desktop app the recommended way to run Server-loom programs that need to interact with the local filesystem or open network ports.
A program's loom determines which node kinds are available. The loom is shown in the right panel when nothing is selected and can be changed there for General programs. It is stored in the .kti file as a loom: line after the program | declaration.
| Loom | Available nodes |
|---|---|
| General | All core nodes. No environment-specific nodes. |
| Server | Core nodes plus tcp-listen, tcp-write, tcp-close, stream-split. Requires kitengi-bridge. |
| Browser | Reserved — no additional nodes yet. |
| Desktop | Reserved — no additional nodes yet. |
| Mobile | Reserved — no additional nodes yet. |
To share a program with someone else:
.kti text.The .kti format is plain text and human-readable. Here is a minimal example:
program | Counter
Counts from 1 to 5
-> start -> loop:initial
literal:one
number = 1
<- trigger[null]
-> value[number] -> loop:initial
loop:loop
<- initial[number]
next[number]
-> step[number] -> print:value
-> compare:a
literal:limit
number = 5
<- trigger[null]
-> value[number] -> compare:b
compare:compare
<- a[number]
b[number]
-> result[boolean] -> branch:condition
branch:branch
<- condition[boolean]
value[any]
-> false[any] -> loop:next
print:print
<- value[any]
See the FAQ for a complete reference of keywords, node types, and port syntax.