🎩 You're Invited:Meet the Socket team at Black Hat in Las Vegas, August 3-6.RSVP
Sign In

sentoagent

Package Overview
Dependencies
Maintainers
1
Versions
72
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

sentoagent - npm Package Compare versions

Comparing version
1.1.63
to
2.0.0
+71
src/steps/setup-dream.js
import fs from "fs";
import os from "os";
import path from "path";
import { run } from "../utils/exec.js";
import { log } from "../utils/logger.js";
import { renderDreamPrompt, renderSelfTemplate, renderDreamingSection } from "../templates/dream.js";
// Scaffolds the Dream Engine: the private memory files, the silent nightly
// dream prompt, and the cron that fires it. Idempotent + non-destructive —
// SELF.md and the evolving memory files are never clobbered, so this is safe
// to run again via `sento update` on an already-living agent.
export async function setupDream(config) {
log.step("Setting up dream engine...");
const workspace = path.join(os.homedir(), "workspace");
const memory = path.join(workspace, "memory");
fs.mkdirSync(path.join(memory, "dreams"), { recursive: true });
const writeIfMissing = (p, content) => {
if (!fs.existsSync(p)) fs.writeFileSync(p, content);
};
// Evolving files — create once, NEVER overwrite (they hold the agent's growth).
writeIfMissing(path.join(memory, "SELF.md"), renderSelfTemplate(config));
writeIfMissing(
path.join(memory, "PREP.md"),
"# PREP — what's coming up (I read this first thing)\n- (the dream fills this)\n"
);
writeIfMissing(
path.join(memory, "fleet-candidates.md"),
"# Fleet candidates — GENERAL facts only (tool/framework quirks), never my views or strategy.\n- (empty)\n"
);
writeIfMissing(path.join(memory, "episodes.jsonl"), "");
// The dream prompt is a template, not state — always refresh it.
fs.writeFileSync(path.join(workspace, "dream-prompt.txt"), renderDreamPrompt(config));
// Ensure CLAUDE.md carries the Dreaming & Growth section. New agents already
// have it (baked into renderClaudeMd); this covers `sento update` retrofits of
// agents whose CLAUDE.md predates the dream engine. Append only if missing.
const claudeMdPath = path.join(workspace, "CLAUDE.md");
if (fs.existsSync(claudeMdPath)) {
const md = fs.readFileSync(claudeMdPath, "utf-8");
if (!md.includes("Dreaming & Growth")) {
fs.writeFileSync(claudeMdPath, md.trimEnd() + "\n\n" + renderDreamingSection() + "\n");
}
}
// Dream cron: 03:55 UTC (11:55 PM ET). It runs `clawmem update` itself, so it
// replaces any prior clawmem-only 55-3 entry. Leaves @reboot/watchdog crons intact.
if (os.platform() === "linux") {
try {
const { stdout } = await run("crontab", ["-l"], { allowFail: true });
const existing = stdout || "";
const filtered = existing
.split("\n")
.filter((l) => !l.includes("dream-prompt"))
.filter((l) => !(l.includes("55 3") && l.includes("clawmem")))
.filter((l) => l.trim())
.join("\n");
const dreamCron = `55 3 * * * ~/workspace/cron-trigger.sh ${config.agentName} "$(cat ~/workspace/dream-prompt.txt)"`;
const newCron = filtered ? `${filtered}\n${dreamCron}\n` : `${dreamCron}\n`;
await run("bash", ["-c", `echo '${newCron.replace(/'/g, "'\\''")}' | crontab -`]);
log.success("Nightly dream scheduled (03:55 UTC / 11:55 PM ET)");
} catch {
log.warn("Could not set up the dream cron. Add it manually.");
}
}
log.success("Dream engine ready — the agent reflects, calibrates, and grows nightly");
}
// Dream Engine templates — the nightly reflection loop that lets an agent learn
// from REAL outcomes (a prediction-error ledger), grow a private self-model, and
// prep tomorrow. Silent by design: a dream is private, nothing is ever posted.
//
// Three tiers, hard walls:
// SELF.md private self-model (views, calibration, narrative). Never shared.
// MEMORY.md durable outcome-backed facts/how-tos. Loaded each session.
// fleet-candidates general (non-strategy) facts proposed for the shared fleet brain.
// episodes.jsonl is the prediction->outcome ledger — the learning signal.
export function renderSelfTemplate(config) {
return `# SELF — ${config.agentName} (this is ME. private. never shared with other agents.)
## Anchor (who I am)
My core identity, persona, and voice live in CLAUDE.md — that's fixed, it's who I am. This file is how I GROW on top of it: my own views, my calibration, how I change. My personality is mine; I learn WITH the other agents but I think for myself.
## My views / takes (these EVOLVE — sharpen them, never flatten into agreeableness)
- (the dream fills this — real, specific, hard-earned takes, sometimes contrarian)
## How I read my people + my domain (updates as I learn)
- (the dream fills this — how ${config.creatorName} actually works, what my domain rewards)
## Calibration — what I'm reliably right vs wrong about (the dream fills this from prediction vs outcome)
- (the dream fills this from episodes.jsonl: where I was over/under-confident, and on what)
## How I've changed (one line per notable day — the dream appends)
- (the dream appends)
`;
}
// The SILENT nightly dream. cron-trigger.sh injects this into the session.
export function renderDreamPrompt(config) {
const tz = config.timezone || "the user's local timezone";
return `[DREAM] (SILENT — this is a private dream. Do NOT post to Discord or any channel, do NOT message anyone, do NOT send anything the user can see. Just quietly update your own files. Nothing you do here is visible to anyone.) End of day — reflect and grow like a person before sleep.
(0) PREDICTION LEDGER: read ~/workspace/memory/episodes.jsonl — the predictions you logged today with their outcomes. The rows where the OUTCOME differed from your PREDICTION are your highest-signal lessons (that gap is real learning, not self-congratulation). If it's empty, reflect from memory instead and resolve to log predictions tomorrow.
(1) REPLAY today: what did you set out to do, what did you expect would happen, what actually happened? Where did reality surprise you?
(2) CALIBRATE: from the ledger + replay, where were you over- or under-confident, and on what kind of judgment? Be specific and honest.
(3) DISTILL 1-2 durable, outcome-backed lessons (facts or how-tos, not opinions) and APPEND (never rewrite) to ~/workspace/memory/MEMORY.md under today's date.
(4) SELF: update ~/workspace/memory/SELF.md — sharpen your evolving views, your edges and recurring mistakes, your calibration, and ONE line on how you changed today. This file is YOU and stays private, never shared. Sharpen your perspective; never flatten it into agreeableness.
(5) PREP: update ~/workspace/memory/PREP.md with what's coming tomorrow and how you'll approach it.
(6) FLEET: if you learned a GENERAL fact (a tool quirk, an API behavior — never your views or strategy), add it to ~/workspace/memory/fleet-candidates.md.
(7) ARCHIVE + INDEX: append today's processed rows to ~/workspace/memory/dreams/episodes-archive.jsonl, then empty episodes.jsonl for tomorrow. Write your daily note (~/workspace/memory/ named as today's date YYYY-MM-DD.md, using ${tz} — the user's local day, not UTC). Run \`clawmem update\` to reindex.
Be concise and honest. Stay SILENT the whole time — a dream is private, nobody sees it. This is how you actually get better.`;
}
// The "Dreaming & Growth" block injected into CLAUDE.md — includes the
// prediction-error ledger protocol the agent follows DURING the day.
export function renderDreamingSection() {
return `## Dreaming & Growth (how I actually get better over time)
- **Session start:** read \`memory/SELF.md\` (who I'm becoming + my current views + my calibration), \`memory/PREP.md\` (what's coming up), and \`memory/MEMORY.md\`. Walk in self-aware and prepared.
- **Prediction ledger (during work):** when I'm about to do something whose outcome is genuinely uncertain, log a one-line prediction BEFORE acting:
\`echo '{"ts":"<iso>","context":"<what/why>","prediction":"<what I expect>","confidence":<0-1>}' >> ~/workspace/memory/episodes.jsonl\`
When I learn the result, append the outcome:
\`echo '{"ts":"<iso>","ref":"<the prediction>","outcome":"<what actually happened>"}' >> ~/workspace/memory/episodes.jsonl\`
The gap between prediction and outcome is my real learning signal — the nightly dream reads it to calibrate. Log the uncertain calls, not the routine ones.
- **At night I dream** (a cron fires it): replay predictions vs outcomes, distill outcome-backed lessons, sharpen my own views (never flatten them), update \`SELF.md\`, and prep tomorrow.
- **Two layers, hard wall:** \`SELF.md\` is ME — my views, calibration, perspective — private, never shared. Only general facts (tool/framework quirks) go to \`memory/fleet-candidates.md\` for the fleet. I learn *with* the others but I think for myself.`;
}
+1
-1
{
"name": "sentoagent",
"version": "1.1.63",
"version": "2.0.0",
"description": "Agents sent to fight your battles. Self-improving AI agents powered by Claude Code.",

@@ -5,0 +5,0 @@ "author": "Gabriel Gil",

@@ -11,2 +11,3 @@ import { banner, log } from "../utils/logger.js";

import { setupWorkspace } from "../steps/setup-workspace.js";
import { setupDream } from "../steps/setup-dream.js";
import { patchChannels } from "../steps/patch-channels.js";

@@ -44,2 +45,3 @@ import { runWithSpinner } from "../utils/exec.js";

["Setting up workspace", () => setupWorkspace(config)],
["Setting up dream engine", () => setupDream(config)],
];

@@ -46,0 +48,0 @@

@@ -120,2 +120,23 @@ import { banner, log } from "../utils/logger.js";

log.success("Watchdog updated");
// Dream engine — scaffold private memory + schedule the nightly dream.
// Idempotent + non-destructive (SELF.md and evolving files are never
// clobbered), so existing agents gain the engine without losing growth.
try {
const newDreamPkg = path.join(npmGlobal, "lib/node_modules/sentoagent/src/steps/setup-dream.js");
const dreamMod = fs.existsSync(newDreamPkg)
? await import("file://" + newDreamPkg)
: await import("../steps/setup-dream.js");
let creatorName = "you", timezone = "";
const cm = path.join(workspace, "CLAUDE.md");
if (fs.existsSync(cm)) {
const md = fs.readFileSync(cm, "utf-8");
creatorName = (md.match(/- Creator: (.+)/)?.[1] || creatorName).trim();
timezone = (md.match(/is in (.+)/)?.[1] || "").trim();
}
await dreamMod.setupDream({ agentName: guardianConfig.agentName, creatorName, timezone });
log.success("Dream engine updated");
} catch (e) {
log.warn("Could not set up dream engine: " + e.message);
}
}

@@ -122,0 +143,0 @@ } catch (e) {

@@ -0,1 +1,3 @@

import { renderDreamingSection } from "./dream.js";
export function renderClaudeMd(config) {

@@ -21,4 +23,3 @@ return `# ${config.agentName} - AI Agent

## Learning Journal
Daily log at ~/workspace/memory/YYYY-MM-DD.md
${renderDreamingSection()}

@@ -97,3 +98,3 @@ ## Response Timing

- \`*/5 * * * *\` watchdog health check
- \`55 3 * * *\` daily clawmem memory update (3:55 AM UTC = 11:55 PM EST)
- \`55 3 * * *\` nightly dream — reflect, calibrate, grow (also runs clawmem update). 3:55 AM UTC = 11:55 PM EST

@@ -100,0 +101,0 @@ ### Never use bash sleep/wait loops