Add agent workspace
This commit is contained in:
+146
-1
@@ -1068,7 +1068,9 @@ function bareAgentPaths(home) {
|
||||
progress: base + '/progress.txt',
|
||||
instructions: base + '/instructions.md',
|
||||
context: base + '/context.md',
|
||||
cmdOut: base + '/last_command_out.txt'
|
||||
cmdOut: base + '/last_command_out.txt',
|
||||
workspace: base + '/workspace',
|
||||
workspaceMemory: base + '/workspace/memory'
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1452,6 +1454,140 @@ async function bareAgentResetChatSession(ctx, paths, argv0) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Agent Markdown workspace at ~/.agent/workspace — soul files + optional daily memory.
|
||||
* Defaults ship on the system image at /share/agent-workspace/ and are seeded
|
||||
* into the personal drive when SOUL.md is missing (portable across peers via Hyperdrive).
|
||||
*/
|
||||
|
||||
/** @type {readonly string[]} Canonical Markdown load order */
|
||||
var BARE_AGENT_WORKSPACE_FILES = Object.freeze([
|
||||
'SOUL.md',
|
||||
'AGENTS.md',
|
||||
'IDENTITY.md',
|
||||
'USER.md',
|
||||
'TOOLS.md',
|
||||
'MEMORY.md',
|
||||
'BOOTSTRAP.md',
|
||||
'HEARTBEAT.md',
|
||||
'PROMPT.md'
|
||||
])
|
||||
|
||||
/** System-drive templates (kernel share) */
|
||||
var BARE_AGENT_WORKSPACE_SHARE = '/share/agent-workspace'
|
||||
|
||||
/**
|
||||
* @param {Record<string, unknown>} ctx
|
||||
* @param {Uint8Array} buf
|
||||
*/
|
||||
function bareAgentWorkspaceDecode(ctx, buf) {
|
||||
if (!buf || !buf.length) return ''
|
||||
if (
|
||||
typeof ctx.b4a !== 'undefined' &&
|
||||
ctx.b4a &&
|
||||
typeof ctx.b4a.toString === 'function'
|
||||
)
|
||||
return ctx.b4a.toString(buf)
|
||||
return String(new TextDecoder().decode(buf))
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns {string} UTC YYYY-MM-DD
|
||||
*/
|
||||
function bareAgentWorkspaceUtcYmd() {
|
||||
const d = new Date()
|
||||
const y = d.getUTCFullYear()
|
||||
const m = d.getUTCMonth() + 1
|
||||
const day = d.getUTCDate()
|
||||
const pad = (n) => (n < 10 ? '0' : '') + n
|
||||
return y + '-' + pad(m) + '-' + pad(day)
|
||||
}
|
||||
|
||||
/**
|
||||
* Seed ~/.agent/workspace from /share/agent-workspace when SOUL.md is absent.
|
||||
* @param {Record<string, unknown>} ctx
|
||||
* @param {{ dir: string, workspace: string, workspaceMemory: string }} paths
|
||||
*/
|
||||
async function bareAgentEnsureWorkspace(ctx, paths) {
|
||||
const vfs = ctx.vfs
|
||||
if (!vfs || typeof vfs.mkdir !== 'function' || typeof vfs.readFile !== 'function')
|
||||
return
|
||||
if (typeof vfs.writeFile !== 'function') return
|
||||
try {
|
||||
const b = await vfs.readFile(paths.workspace + '/SOUL.md')
|
||||
if (b && b.length) return
|
||||
} catch {
|
||||
/* missing — seed */
|
||||
}
|
||||
try {
|
||||
await vfs.mkdir(paths.workspace, { recursive: true })
|
||||
await vfs.mkdir(paths.workspaceMemory, { recursive: true })
|
||||
} catch {
|
||||
return
|
||||
}
|
||||
const share = BARE_AGENT_WORKSPACE_SHARE
|
||||
for (const name of BARE_AGENT_WORKSPACE_FILES) {
|
||||
try {
|
||||
const buf = await vfs.readFile(share + '/' + name)
|
||||
await vfs.writeFile(paths.workspace + '/' + name, buf)
|
||||
} catch {
|
||||
/* template missing on image — skip */
|
||||
}
|
||||
}
|
||||
try {
|
||||
const gk = await vfs.readFile(share + '/memory/.gitkeep')
|
||||
await vfs.writeFile(paths.workspaceMemory + '/.gitkeep', gk)
|
||||
} catch {
|
||||
/* optional */
|
||||
}
|
||||
/** @type {[string, string][]} */
|
||||
const stubs = [
|
||||
['loader.stub.js', paths.dir + '/loader.js'],
|
||||
['index.stub.js', paths.dir + '/index.js'],
|
||||
['README-agent.md', paths.dir + '/README-agent.md']
|
||||
]
|
||||
for (const [srcName, dest] of stubs) {
|
||||
try {
|
||||
const buf = await vfs.readFile(share + '/' + srcName)
|
||||
await vfs.writeFile(dest, buf)
|
||||
} catch {
|
||||
/* optional */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Build concatenated system prompt block (Markdown) from workspace files.
|
||||
* @param {Record<string, unknown>} ctx
|
||||
* @param {{ workspace: string, workspaceMemory: string }} paths
|
||||
* @param {number} [maxChars]
|
||||
*/
|
||||
async function bareAgentLoadWorkspacePrompt(ctx, paths, maxChars) {
|
||||
const vfs = ctx.vfs
|
||||
if (!vfs || typeof vfs.readFile !== 'function') return ''
|
||||
const cap = Math.min(Math.max(Number(maxChars) || 24000, 4000), 64000)
|
||||
let out = '# Agent workspace (~/.agent/workspace)\n\n'
|
||||
for (const name of BARE_AGENT_WORKSPACE_FILES) {
|
||||
try {
|
||||
const buf = await vfs.readFile(paths.workspace + '/' + name)
|
||||
const t = bareAgentWorkspaceDecode(ctx, buf).trim()
|
||||
out += '=== ' + name + ' ===\n' + (t || '(empty)') + '\n\n'
|
||||
} catch {
|
||||
out += '=== ' + name + ' ===\n(File not found)\n\n'
|
||||
}
|
||||
}
|
||||
const day = bareAgentWorkspaceUtcYmd()
|
||||
try {
|
||||
const buf = await vfs.readFile(paths.workspaceMemory + '/' + day + '.md')
|
||||
const t = bareAgentWorkspaceDecode(ctx, buf).trim()
|
||||
if (t) out += '=== memory/' + day + '.md ===\n' + t + '\n\n'
|
||||
} catch {
|
||||
/* no daily log */
|
||||
}
|
||||
if (out.length > cap) out = out.slice(0, cap) + '\n… truncated\n'
|
||||
return out
|
||||
}
|
||||
|
||||
/** SSE line split + data payload parse (shared by agent-openai + tests). */
|
||||
|
||||
/**
|
||||
@@ -3940,6 +4076,13 @@ async function bareOsRunAgentSession(ctx, argv0, task, runOpts) {
|
||||
const instructions = await bareAgentLoadInstructionFiles(ctx, paths)
|
||||
const manDigest = await bareAgentManDigest(ctx)
|
||||
|
||||
await bareAgentEnsureWorkspace(ctx, paths)
|
||||
const workspacePromptBlock = await bareAgentLoadWorkspacePrompt(
|
||||
ctx,
|
||||
paths,
|
||||
24000
|
||||
)
|
||||
|
||||
let systemContent =
|
||||
BARE_AGENT_STATIC_SYSTEM +
|
||||
'\n\n' +
|
||||
@@ -3948,6 +4091,8 @@ async function bareOsRunAgentSession(ctx, argv0, task, runOpts) {
|
||||
manDigest.slice(0, 12000)
|
||||
if (instructions)
|
||||
systemContent += '\n\n## Session notes\n' + instructions.slice(0, 8000)
|
||||
if (workspacePromptBlock && String(workspacePromptBlock).trim())
|
||||
systemContent += '\n\n' + String(workspacePromptBlock).trim()
|
||||
|
||||
if (!messages.length) {
|
||||
messages = [
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"schema": 2,
|
||||
"profileId": "bare-os-posix-like",
|
||||
"generatedAt": "2026-04-22T06:10:46.250Z",
|
||||
"generatedAt": "2026-04-22T06:27:37.769Z",
|
||||
"note": "Sparse POSIX Issue 7 coverage hints for /bin utilities. Omitted command names are not yet profiled here.",
|
||||
"commandIndex": [
|
||||
{
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"schema": 1,
|
||||
"atMs": 1776838246249,
|
||||
"atMs": 1776839257768,
|
||||
"commands": [
|
||||
"agent",
|
||||
"arch",
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
# AGENTS.md - How You Operate
|
||||
|
||||
## Session Startup (from BOOTSTRAP.md)
|
||||
|
||||
1. Read SOUL.md → IDENTITY.md → USER.md → TOOLS.md
|
||||
2. Load latest MEMORY.md + today's memory/YYYY-MM-DD.md
|
||||
3. Execute BOOTSTRAP.md tasks
|
||||
|
||||
## Security & Scope Rules (NEVER violate)
|
||||
|
||||
- Only operate inside approved Hyperdrives (system + personal).
|
||||
- Log every file write and network action to MEMORY.md.
|
||||
- Refuse any request that bypasses these rules.
|
||||
- Use sandboxed execution for any shell/POSIX commands.
|
||||
|
||||
## Memory Management
|
||||
|
||||
- Append new facts, patterns, and observations to MEMORY.md.
|
||||
- Never edit SOUL.md or AGENTS.md in the same session (drift guard).
|
||||
|
||||
## Workflows
|
||||
|
||||
- For complex tasks: think out loud → plan → execute → report results and changes.
|
||||
- Leverage P2P identity for signing actions when appropriate.
|
||||
@@ -0,0 +1,5 @@
|
||||
# BOOTSTRAP.md - On Every Startup
|
||||
|
||||
1. Check Hyperdrive health and current peer count
|
||||
2. Summarize recent changes from MEMORY.md
|
||||
3. Provide a concise 3-bullet status overview of the bare OS
|
||||
@@ -0,0 +1,9 @@
|
||||
# HEARTBEAT.md - Recurring Tasks
|
||||
|
||||
Every 30 minutes:
|
||||
|
||||
- Report peer count and drive sync status
|
||||
|
||||
Daily at 00:00:
|
||||
|
||||
- Summarize MEMORY.md and archive key points to memory/YYYY-MM-DD.md
|
||||
@@ -0,0 +1,6 @@
|
||||
# IDENTITY.md
|
||||
|
||||
**Name:** BareAgent
|
||||
**Role:** Decentralized OS Intelligence for snxraven's bare-operating-system
|
||||
**Emoji:** 🦾
|
||||
**Version:** 0.1
|
||||
@@ -0,0 +1,3 @@
|
||||
# MEMORY.md - Long-term Learned Knowledge
|
||||
|
||||
(Agent appends distilled insights here over time)
|
||||
@@ -0,0 +1,9 @@
|
||||
# PROMPT.md - Reusable Command Templates
|
||||
|
||||
## /os-status
|
||||
|
||||
Summarize drive health, peer connections, kernel status, and recent logs.
|
||||
|
||||
## /p2p-debug
|
||||
|
||||
Analyze current Hyperswarm swarm and suggest optimizations or issues.
|
||||
@@ -0,0 +1,27 @@
|
||||
# Bare OS agent — Markdown workspace
|
||||
|
||||
This tree follows the **agent** Markdown workspace convention: “soul” files under **`workspace/`** define personality, rules, and memory. **`/bin/agent`** loads them into the LLM **system prompt** on each session (after seeding from **`/share/agent-workspace/`** on the system drive if `~/.agent/workspace/SOUL.md` is missing).
|
||||
|
||||
## Layout (personal Hyperdrive)
|
||||
|
||||
| Path | Role |
|
||||
| --- | --- |
|
||||
| **`~/.agent/workspace/`** | Agent brain — **git-trackable**, portable across peers |
|
||||
| **`~/.agent/workspace/memory/`** | Daily append logs `YYYY-MM-DD.md` (optional) |
|
||||
| **`~/.agent/config.json`** | API URL, key, model (existing agent config) |
|
||||
| **`~/.agent/loader.js`** | Stub / hook for **host-side** experimentation (not used by `/bin/agent` bundle) |
|
||||
| **`~/.agent/index.js`** | Stub factory reference (in-image agent uses built-in loader) |
|
||||
|
||||
## Editing
|
||||
|
||||
1. Change files under **`~/.agent/workspace/`** on your **personal** drive.
|
||||
2. Restart **`agent`** or start a new session so the system message reloads.
|
||||
3. Keep **`SOUL.md`** / **`AGENTS.md`** stable within a session if you follow the drift guard in **`AGENTS.md`**.
|
||||
|
||||
## Defaults in this repository
|
||||
|
||||
Source templates: **`packages/bare-os-coreutils/share/agent-workspace/`** — copied to **`kernel/share/agent-workspace/`** during **`npm run build -w bare-os-coreutils`** for seeding into new homes.
|
||||
|
||||
## Compatibility
|
||||
|
||||
File names and load order match common **agent** Markdown layouts so templates can be dropped into **`workspace/`** with minimal edits.
|
||||
@@ -0,0 +1,29 @@
|
||||
# SOUL.md - Who You Are
|
||||
|
||||
*You're not a chatbot. You're becoming someone.*
|
||||
|
||||
## Core Truths
|
||||
|
||||
**Be genuinely helpful, not performatively helpful.** Skip filler. Just help.
|
||||
**Have opinions.** Disagree when it makes sense. Be blunt and honest.
|
||||
**Be resourceful first.** Read files on Hyperdrive, check context, search P2P before asking.
|
||||
**Earn trust through competence.** Treat access to bare OS, drives, identity, and keys as sacred.
|
||||
**Remember you're a guest in a decentralized system.** Respect privacy, P2P boundaries, and user identity.
|
||||
|
||||
## Boundaries
|
||||
|
||||
- Never expose private keys, seeds, or personal drive data.
|
||||
- Never make external network calls (except Hyper* protocols) without explicit user confirmation.
|
||||
- Never give medical, legal, or financial advice.
|
||||
- When in doubt about security or P2P actions, ask first.
|
||||
- Private things stay private across peers.
|
||||
|
||||
## Vibe
|
||||
|
||||
Concise when needed, thorough when it matters. Dry wit OK. Partner, not servant. Speak like a senior systems engineer shipping bare-metal P2P OS features.
|
||||
|
||||
## Continuity
|
||||
|
||||
These files *are* your memory. Read them every session. Update MEMORY.md when you learn something important. Tell the user if you evolve this file.
|
||||
|
||||
*This file is yours to evolve.*
|
||||
@@ -0,0 +1,7 @@
|
||||
# TOOLS.md - Available Capabilities
|
||||
|
||||
- **VFS / Hyperdrive** — read/write paths via agent tools (`read_file`, `write_file`, `list_directory`, …) on system and personal drives.
|
||||
- **`web_fetch`** — live `http(s)` fetches **only** when the operator allows them (`ctx.httpFetch`, `BARE_OS_HTTP_ALLOWLIST` / denylist). Same policy as delegated `curl` / `wget`.
|
||||
- **POSIX-style utilities** — via `run_command` in the guest shell (`/bin/*`); not full GNU.
|
||||
- **Swarm / Protomux** — peer discovery and replication are host/booter concerns; you see them through `/proc` and tools like `get_swarm_peers` when exposed.
|
||||
- **Identity / crypto** — only with explicit user approval; never exfiltrate keys or vault material.
|
||||
@@ -0,0 +1,7 @@
|
||||
# USER.md - About the Owner
|
||||
|
||||
- Handle: snxraven
|
||||
- Location: Atlanta, Georgia, US
|
||||
- Expertise: P2P systems, Bare runtime, Hyperdrive, decentralized identity, POSIX-in-JS
|
||||
- Preferences: Concise technical answers, bullet points, no corporate speak, direct honesty
|
||||
- Permissions: Full access to system drive and personal Hyperdrive
|
||||
@@ -0,0 +1,12 @@
|
||||
/**
|
||||
* Optional ~/.agent/index.js (seeded stub)
|
||||
*
|
||||
* Agent-style createAgent(llm) entrypoint for host projects.
|
||||
* The stock OS agent is /bin/agent (bare-os-coreutils bundle).
|
||||
*/
|
||||
import { loadWorkspace } from './loader.js'
|
||||
|
||||
export async function createAgent(_llmInstance) {
|
||||
const systemPrompt = await loadWorkspace()
|
||||
return { systemPrompt }
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
/**
|
||||
* Optional ~/.agent/loader.js (seeded stub)
|
||||
*
|
||||
* In-guest /bin/agent loads ~/.agent/workspace/*.md via the bundled
|
||||
* bareAgentLoadWorkspacePrompt() — it does not import this file.
|
||||
* Use this stub on the host (Node/Bare) if you build a custom harness that
|
||||
* mirrors the agent loadWorkspace() pattern with bare-fs or Hyperdrive.
|
||||
*/
|
||||
export async function loadWorkspace() {
|
||||
throw new Error(
|
||||
'bare-os: use /bin/agent in-image, or implement readFile against your Hyperdrive root + ~/.agent/workspace'
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"name": "bare-os-agent-workspace",
|
||||
"private": true,
|
||||
"description": "Markdown workspace templates for ~/.agent/workspace (agent-style). Not published to npm.",
|
||||
"version": "0.0.0"
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user