aboutsummaryrefslogtreecommitdiff
path: root/docs/usage.html
blob: 52314fa304ce473e2c1fbd21e10f2c590f2fdd32 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Getting newOS4 — Linux, macOS, Windows, Termux</title>
<meta name="description" content="How to clone the newOS4 repository on Linux, macOS, Windows and Android (Termux).">
<style>
  :root { --bg:#0b0d10; --panel:#14171c; --line:#252b34; --text:#e6e8ec; --dim:#9aa4b2; --accent:#8b9cf7; }
  * { box-sizing: border-box; }
  body { margin:0; background:var(--bg); color:var(--text);
         font:16px/1.65 -apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Helvetica,Arial,sans-serif; }
  .wrap { max-width: 860px; margin: 0 auto; padding: 32px 20px 72px; }
  h1 { font-size: 1.7rem; margin: 0 0 6px; letter-spacing:-.02em; }
  .lede { color: var(--dim); margin: 0 0 26px; }
  h2 { font-size: 1.15rem; margin: 34px 0 10px; padding-bottom: 6px; border-bottom: 1px solid var(--line); }
  h3 { font-size: 1rem; margin: 22px 0 6px; }
  p, li { color: var(--text); }
  a { color: var(--accent); }
  code { font-family: ui-monospace,SFMono-Regular,Menlo,Consolas,monospace; font-size: .88em;
         background: #1b2027; padding: 1px 5px; border-radius: 4px; }
  pre { background: var(--panel); border: 1px solid var(--line); border-radius: 10px;
        padding: 14px 16px; overflow-x: auto; margin: 10px 0 4px; }
  pre code { background: none; padding: 0; font-size: .86rem; line-height: 1.55; display: block; }
  .panel { background: var(--panel); border: 1px solid var(--line); border-radius: 12px;
           padding: 18px 20px; margin: 14px 0; }
  /* minmax(0,1fr) + min-width:0: a grid item defaults to min-width:auto, so one long
     command line in a <pre> stretches the whole column past the viewport (measured 521 px
     of content in a 390 px screen before this). */
  .os { display:grid; gap:14px; grid-template-columns: minmax(0,1fr); }
  .os > div { min-width: 0; }
  pre { max-width: 100%; }
  .kv { display:grid; grid-template-columns: max-content 1fr; gap: 6px 18px; margin: 8px 0 0; font-size:.9rem; }
  .kv dt { color: var(--dim); }
  .kv dd { margin:0; }
  .tag { font-size:.72rem; text-transform:uppercase; letter-spacing:.08em; color:var(--dim);
         border:1px solid var(--line); border-radius:999px; padding:2px 9px; }
  /* fixed layout + wrapping: the troubleshooting table has a column of long <code> strings
     and without this it forced the page 75 px wider than a 390 px viewport. */
  table { width:100%; border-collapse:collapse; margin-top:10px; font-size:.9rem;
          table-layout: fixed; }
  td, th { overflow-wrap: anywhere; word-break: break-word; }
  th, td { text-align:left; padding:7px 10px 7px 0; border-bottom:1px solid var(--line); vertical-align:top; }
  th { color:var(--dim); font-weight:600; }
  .warn { border-left:3px solid #d9a441; padding-left:14px; color:#e8d3a8; margin:12px 0; }
  footer { margin-top:44px; padding-top:14px; border-top:1px solid var(--line); color:var(--dim); font-size:.85rem; }
</style>
</head>
<body>
<div class="wrap">

<h1>Getting newOS4</h1>
<p class="lede">One public, read-only repository. Clone it on Linux, macOS, Windows or Android — no account,
no key, no token.</p>

<div class="panel">
  <pre><code>git clone https://newos.webx11.duckdns.org/newos4.git</code></pre>
  <p style="margin:8px 0 0;color:var(--dim);font-size:.9rem">
    One URL for every platform. <code>…/newos4</code> (without <code>.git</code>) also works — that is cgit's
    dumb-HTTP path and it is slower; use the <code>.git</code> form.</p>
</div>

<table>
  <tr><th>What you get</th><th></th></tr>
  <tr><td>Contents</td><td>The whole tree &mdash; a few MB &mdash; with full history, MIT licence</td></tr>
  <tr><td>Latest tag</td><td><code>v4.6.146</code> — <a href="/newos4/refs/">see refs</a></td></tr>
  <tr><td>Writes</td><td>none. <code>git-receive-pack</code> answers 403; there is no SSH endpoint</td></tr>
  <tr><td>Private data</td><td>stripped from every commit before publication — see <a href="/usage.html#scope">Scope</a></td></tr>
  <tr><td>Reading it</td><td><a href="/newos4/about/">rendered README</a> · <a href="/newos4/tree/">file tree</a> · <a href="/newos4/log/">history</a></td></tr>
</table>

<h2 id="linux">Linux</h2>
<div class="os">
  <div>
    <h3>Install git, if it is missing</h3>
    <pre><code># Debian / Ubuntu / Mint
sudo apt update &amp;&amp; sudo apt install -y git

# Fedora / RHEL
sudo dnf install -y git

# Arch / Manjaro
sudo pacman -S --noconfirm git

# Alpine
sudo apk add git</code></pre>
  </div>
  <div>
    <h3>Clone and check</h3>
    <pre><code>git --version                       # 2.30 or newer is fine
git clone https://newos.webx11.duckdns.org/newos4.git
cd newos4
git log --oneline -3
git describe --tags                 # v4.6.146</code></pre>
  </div>
</div>
<p style="color:var(--dim);font-size:.9rem">A distro without CA roots fails with
<code>SSL certificate problem</code>: install <code>ca-certificates</code>. Behind a proxy, add
<code>git config --global http.proxy http://host:port</code>.</p>

<h2 id="macos">macOS</h2>
<pre><code>xcode-select --install      # ships git (Apple's build is older but sufficient)
# or: brew install git

git clone https://newos.webx11.duckdns.org/newos4.git
cd newos4 &amp;&amp; git describe --tags</code></pre>
<p style="color:var(--dim);font-size:.9rem">If <code>git</code> opens a licence prompt, run
<code>sudo xcodebuild -license accept</code> once. The clone lands in your working directory; nothing is
installed system-wide.</p>

<h2 id="windows">Windows</h2>
<pre><code>winget install --id Git.Git -e --source winget

# new PowerShell window, then:
git clone https://newos.webx11.duckdns.org/newos4.git
cd newos4
git log --oneline -3</code></pre>
<div class="warn">
  <strong>Set this before cloning on Windows:</strong>
  <code>git config --global core.autocrlf false</code>. The repository is served from a Linux host — a CRLF
  checkout silently rewrites every shell script and JS file, and they stop working when copied back. Linux
  and macOS default to <code>false</code>; Windows installers default to <code>true</code>.
</div>
<p style="color:var(--dim);font-size:.9rem">Without winget: <a href="https://git-scm.com/download/win">git-scm.com/download/win</a>
→ “Git for Windows” → next-next-finish → “Git Bash” gives you the same commands as above. WSL2 works too and
needs no special handling.</p>

<h2 id="android">Android — Termux</h2>
<p>Termux is a real Linux userland, so the Linux instructions apply almost unchanged. Three things differ:</p>
<div class="os">
  <div>
    <h3>1. Install git in Termux</h3>
    <pre><code>pkg update &amp;&amp; pkg upgrade -y
pkg install -y git ca-certificates
git --version</code></pre>
  </div>
  <div>
    <h3>2. Clone into Termux's own home, not shared storage</h3>
    <pre><code>cd ~
git clone https://newos.webx11.duckdns.org/newos4.git
cd newos4
git log --oneline -3</code></pre>
    <div class="warn">
      Do <em>not</em> clone into <code>/sdcard</code> or <code>~/storage/…</code>: that filesystem is
      FUSE-mounted without POSIX permissions, and git dies with
      <code>error: unable to write file … Permission denied</code> halfway through. Clone to
      <code>~/newos4</code> and copy files out afterwards. If you need shared storage access at all, run
      <code>termux-setup-storage</code> once and grant the prompt.
    </div>
  </div>
  <div>
    <h3>3. Keep the session alive for a big clone</h3>
    <pre><code>termux-wake-lock          # stops Android from freezing the download
git clone --depth 1 https://newos.webx11.duckdns.org/newos4.git
termux-wake-unlock</code></pre>
    <p style="color:var(--dim);font-size:.9rem;margin:6px 0 0">
      <code>--depth 1</code> fetches the newest tree only — much faster on mobile data. You lose history;
      re-clone without it later if you want the full history.</p>
  </div>
</div>
<p style="color:var(--dim);font-size:.9rem">Editing on the phone: <code>pkg install nano</code> or
<code>pkg install micro</code>, then <code>nano newos4/README.md</code>. Termux's own git is a standard build, so
<code>git status</code>, <code>git diff</code> and <code>git log</code> behave exactly as on a laptop.</p>

<h2 id="ios">iPhone / iPad</h2>
<p><a href="https://holzschu.github.io/a-Shell_iOS/">a-Shell</a> (free) includes git: run the same
<code>git clone</code> command. <a href="https://workingcopy.app/">Working Copy</a> is a GUI alternative that can
also clone a public HTTPS repository without an account.</p>

<h2 id="pi">Automating with the pi agent</h2>
<p><code>pi</code> is a terminal coding agent (a Node CLI — <code>pi --help</code>). Everything below uses
only documented flags, treats the mirror as read-only, and was run against <code>pi 0.80.3</code> (what this
host had installed — npm currently ships 1.5.0) before being
written down.</p>

<h3>Install</h3>
<pre><code>node -v                       # needs Node &gt;= 22.19.0
npm install -g @earendil-works/pi-coding-agent
pi --version                  # e.g. 1.5.0</code></pre>
<p style="color:var(--dim);font-size:.9rem">That package installs the <code>pi</code> binary
(<code>bin: pi → dist/bundle/cli.js</code>). A system-wide install lands in
<code>/usr/lib/node_modules/@earendil-works/pi-coding-agent</code>; a user install needs
<code>~/.local/bin</code> on <code>PATH</code>.</p>

<h3>Point it at Ollama</h3>
<p>Ollama speaks the OpenAI wire format on <code>http://127.0.0.1:11434/v1</code> by default, which is exactly
what <code>pi</code> expects. Two files under <code>~/.pi/agent/</code> do the whole job:</p>
<pre><code>// ~/.pi/agent/models.json
{
  "providers": {
    "ollama": {
      "baseUrl": "http://localhost:11434/v1",
      "api": "openai-completions",
      "apiKey": "ollama",
      "compat": { "supportsDeveloperRole": false, "supportsReasoningEffort": false },
      "models": [
        { "id": "llama3.2:latest", "name": "Llama 3.2 (local)" },
        { "id": "qwen2.5-coder:7b", "name": "Qwen2.5 Coder 7B (local)" }
      ]
    }
  }
}</code></pre>
<pre><code>// ~/.pi/agent/settings.json
{ "defaultProvider": "ollama", "defaultModel": "llama3.2:latest" }</code></pre>
<p style="color:var(--dim);font-size:.9rem"><code>baseUrl</code> points at your daemon — use
<code>http://localhost:11434/v1</code> for a local Ollama, or your own host:port. <code>apiKey</code> must be a
non-empty string because the client sends it as a bearer token; Ollama ignores the value. The two
<code>compat</code> flags off are what this provider needs.</p>

<div class="warn">
  <strong>Pulling a model in Ollama is not enough.</strong> It must also be listed under
  <code>models[]</code>. Undeclared, <code>pi --model llama3.2:latest</code> fails with
  <code>Error: Model "llama3.2:latest" not found. Use --list-models</code> — that is the single most common
  configuration mistake and it looks like a connection problem.
</div>

<h3>Verify the wiring</h3>
<pre><code>pi --list-models | grep ollama           # your declared ids, with context limits
ollama list                              # what the daemon actually serves
pi -p --no-session --no-tools --model llama3.2:latest "Reply with exactly: LOCAL OK"</code></pre>
<p style="color:var(--dim);font-size:.9rem">A reply of <code>LOCAL OK</code> means the whole chain works:
config → local daemon → model. Ids ending in <code>-cloud</code> are relayed by Ollama to
<code>ollama.com</code> and need an <code>ollama signin</code>; local tags have no suffix.</p>

<h3>1. One-shot: analyse a file, print an answer, exit</h3>
<pre><code>git clone --depth 1 https://newos.webx11.duckdns.org/newos4.git /tmp/newos4

pi -p --no-session --no-tools --model gemma4:31b-cloud \
   @/tmp/newos4/README.md "In one sentence, what is this repository?"</code></pre>
<p style="color:var(--dim);font-size:.9rem">Output: <em>“This repository contains newOS4, a browser-based
terminal featuring a filesystem, command shell, editor, and AI agent backed by WebDAV storage and WebX11 user
spaces.”</em> — <code>-p</code> is the non-interactive mode, <code>@file</code> inlines the file,
<code>--no-tools</code> forbids tool use entirely, <code>--no-session</code> leaves nothing behind.</p>

<h3>2. Machine-readable output for scripts</h3>
<pre><code>pi -p --no-session --no-tools --mode json --model gemma4:31b-cloud \
   @/tmp/newos4/CHANGELOG.md "Summarise the newest release in one line" \
 | jq -r 'select(.type=="message_end" and .message.role=="assistant")
          | .message.content[0].text'</code></pre>
<p style="color:var(--dim);font-size:.9rem"><code>--mode json</code> emits one JSON object per line. The event
types in order are <code>session</code>, <code>agent_start</code>, <code>turn_start</code>,
<code>message_start</code>/<code>message_end</code> (the assistant's text is in
<code>message.content[].text</code>), <code>turn_end</code>, <code>agent_end</code>. Parse on
<code>message_end</code> and you never have to scrape the terminal UI.</p>

<h3>3. Let it read the tree — with a read-only tool allowlist</h3>
<pre><code>cd /tmp/newos4
pi -p --no-session --tools read,bash --no-approve --model gemma4:31b-cloud \
   "Which files does main.html load, and where is the module loader defined?"</code></pre>
<p style="color:var(--dim);font-size:.9rem">Tool names are <code>read</code>, <code>bash</code>,
<code>edit</code>, <code>write</code>; <code>--tools</code> is an allowlist, so leaving <code>edit</code> and
<code>write</code> out makes the run read-only by construction. <code>--tools read</code> alone cannot list a
directory — <code>read</code> reads files — so add <code>bash</code> when it needs to <code>ls</code>.</p>

<h3>Flags worth knowing for automation</h3>
<table>
  <tr><th>Flag</th><th>What it buys you</th></tr>
  <tr><td><code>--list-models</code></td><td>What your install can actually reach, with context and output limits</td></tr>
  <tr><td><code>--model</code></td><td>Pin the model in scripts. A saved default can be retired server-side and fail with HTTP 410 “was retired” — passing <code>--model</code> keeps a job reproducible</td></tr>
  <tr><td><code>--offline</code></td><td>Skip startup network calls (<code>PI_OFFLINE=1</code> also works)</td></tr>
  <tr><td><code>--session-id</code> / <code>--continue</code></td><td>Resume the same conversation across runs instead of re-sending context</td></tr>
  <tr><td><code>--append-system-prompt &lt;file&gt;</code></td><td>Append text or a file's contents to the system prompt — the cheap way to give every run your house rules</td></tr>
  <tr><td><code>--skill &lt;path&gt;</code></td><td>Load a skill file or directory; <code>--no-skills</code> / <code>--no-context-files</code> turn discovery off</td></tr>
</table>

<h3>Safety: this repository is untrusted input</h3>
<div class="warn">
  <code>pi</code> auto-loads project files (<code>AGENTS.md</code>, <code>CLAUDE.md</code>, skills, extensions)
  from the working directory. For a clone of a public repository you did not write, run with
  <code>--no-approve</code> (ignores project-local files) and a tool allowlist that cannot write —
  <code>--tools read</code>, or <code>--tools read,bash</code> if it must list files. Never point a
  full-tool run at a repo you have not read: a prompt-injection in a README is executed the same way your own
  instructions would be.
</div>

<h3>A cron-able digest</h3>
<pre><code>#!/bin/sh
# nightly: refresh the mirror, ask one question, write markdown
set -eu
cd /tmp/newos4 2>/dev/null || git clone -q --depth 1 https://newos.webx11.duckdns.org/newos4.git /tmp/newos4
git pull -q --ff-only
pi -p --no-session --no-tools --mode json --model gemma4:31b-cloud \
   @CHANGELOG.md "Three bullets: what changed in the newest release?" \
 | jq -r 'select(.type=="message_end" and .message.role=="assistant") | .message.content[0].text' \
 &gt; "$HOME/newos4-digest.md"</code></pre>
<p style="color:var(--dim);font-size:.9rem">The mirror only fast-forwards, so <code>git pull --ff-only</code>
can never wedge. Nothing here can push — the repository refuses <code>receive-pack</code> at three levels.</p>

<h2 id="contributing">Contributing (contrib branches)</h2>
<p>The mirror accepts contributions, but only as <strong>contrib branches</strong> — <code>main</code> is
generated from the platform's monorepo and a push to it would be erased by the next publish. Pushes go to
a separate host that asks for credentials; the read-only host in your <code>origin</code> stays anonymous
and read-only.</p>
<pre><code># 1. one token per account: Dashboard -> "Git push token" -> Create (shown once, revocable)
#    (looks like: https://&lt;user&gt;:wx11gp_…@push.newos.webx11.duckdns.org/newos4.git)
git remote add push https://push.newos.webx11.duckdns.org/newos4.git

# 2. work on a branch, push it under contrib/
git switch -c contrib/&lt;your-username&gt;/my-fix
git commit -am "fix(shell): handle an empty command"
git push push HEAD:refs/heads/contrib/&lt;your-username&gt;/my-fix</code></pre>
<p style="color:var(--dim);font-size:.9rem">Use a credential helper rather than pasting the token into the
URL of a repository you might publish. Git will ask once and can remember it
(<code>git config --global credential.helper store</code> writes it to a plain file — choose
<code>cache</code> or your OS keychain if that matters).</p>

<h3>What the server enforces</h3>
<table>
  <tr><th>Rule</th><th>Reason</th></tr>
  <tr><td>Only <code>refs/heads/contrib/&lt;you&gt;/*</code></td><td><code>main</code> and tags are generated by the publisher; a push there would disappear at the next publish. The middle segment must be your own username — the hook compares it to the account that authenticated, so nobody can overwrite a neighbour's branch</td></tr>
  <tr><td>No credentials in the diff</td><td>The repository is public. Every added blob is scanned before it is accepted; a match rejects the whole push with the file name</td></tr>
  <tr><td>No profile or key files</td><td><code>.user.json</code>, <code>.session</code>, <code>.env</code>, <code>*.pem</code>, <code>id_rsa</code> are refused by path</td></tr>
  <tr><td>≤ 200 files, ≤ 2 MB of new content per push</td><td>Keeps one push from making the mirror unusable</td></tr>
  <tr><td>Deleting your own contrib branch</td><td>Allowed — it is your branch</td></tr>
</table>

<h3>What happens after you push</h3>
<p>A moderator triages every branch automatically: docs-only changes are marked <em>ready</em>, anything
touching code is queued for a human with a diff summary, and a branch that breaks a hard rule is deleted.
The queue is visible to the operator; you will hear back on your branch, not in a black hole.</p>
<pre><code>git fetch push 'refs/heads/contrib/*:refs/remotes/contrib/*'
git log --oneline main..contrib/<your-username>/my-fix   # what your branch adds
git push push --delete contrib/<your-username>/my-fix    # withdraw it</code></pre>

<h2 id="updating">Updating later</h2>
<pre><code>cd newos4
git pull --ff-only          # the mirror only ever fast-forwards
git describe --tags         # new tag appears when a release is published</code></pre>
<p style="color:var(--dim);font-size:.9rem">The mirror is refreshed daily at 05:50 UTC and a new release tag is
minted on each publish. Nothing you do locally can be pushed back — see below.</p>

<h2 id="verify">Verifying what you got</h2>
<pre><code>git -C newos4 rev-parse --short HEAD      # tip commit
git -C newos4 tag -l                      # v4.6.146
git -C newos4 ls-files | wc -l            # every published file
git -C newos4 rev-list --count HEAD       # every published commit
du -sh newos4/.git                      # a few MB</code></pre>

<h2 id="scope">Scope, and why you cannot push</h2>
<p>The mirror is generated from a private monorepo by
<code>admin/scripts/publish-newos4.py</code>: it keeps only the <code>spaces/newos4</code> subtree, removes
private paths (<code>data/</code>, <code>backups/</code>, <code>.hermes/</code>, credentials, profile JSON) from
<strong>every commit</strong>, and scans all blobs for secrets before anything is pushed. That is why the history
starts where it does: earlier private commits were never published.</p>
<p>Pushing is disabled at three levels — no <code>git-receive-pack</code> route on the vhost, <code>403</code> on
the advertisement, and <code>http.receivepack=false</code> in the repository. If you want to report a bug or ask
for a change, email <a href="mailto:darkmotox11@gmail.com">darkmotox11@gmail.com</a>; do not send patches to a
repository that cannot accept them.</p>

<h2 id="trouble">Troubleshooting</h2>
<table>
  <tr><th>Symptom</th><th>Cause and fix</th></tr>
  <tr><td><code>Repository not found</code></td><td>Wrong URL. Use <code>https://newos.webx11.duckdns.org/newos4.git</code> — the host is <code>newos.</code>, not <code>git.</code></td></tr>
  <tr><td><code>SSL certificate problem</code></td><td>Missing CA bundle → <code>apt install ca-certificates</code> / <code>pkg install ca-certificates</code></td></tr>
  <tr><td><code>Could not resolve host</code></td><td>Offline, or a corporate DNS that drops wildcard subdomains</td></tr>
  <tr><td><code>403</code> on <code>git push</code></td><td>Expected — the mirror is read-only by design</td></tr>
  <tr><td>Clone stalls on mobile</td><td><code>git clone --depth 1</code>, and <code>termux-wake-lock</code> on Android</td></tr>
  <tr><td>Scripts arrive with CRLF</td><td><code>git config --global core.autocrlf false</code>, then re-clone</td></tr>
</table>

<footer>
  Served from the same repository it documents ·
  Source: <a href="/newos4/tree/docs/usage.html">docs/usage.html</a> ·
  <a href="/newos4/about/">README</a> · MIT licence · updated 2026-11-05
</footer>

</div>
</body>
</html>