Prime Agent 快速入门:给模型一个 REPL,不是一堆按钮
:root{
–bg:#0b1020; –bg2:#0d1426; –card:#121a30; –panel:#0a0f1e;
–ink:#e9edf6; –mut:#9aa7c2; –dim:#6d7a96; –line:#223050;
–or:#ffab4a; –te:#3ddbc4; –ye:#ffd84d; –rd:#ff6b7a; –bl:#6aa6ff; –pu:#b48cff;
–sans:-apple-system,BlinkMacSystemFont,’Segoe UI’,’Noto Sans SC’,’PingFang SC’,’Microsoft YaHei’,sans-serif;
–mono:’Cascadia Code’,’JetBrains Mono’,Consolas,’SFMono-Regular’,monospace;
}
*{margin:0;padding:0;box-sizing:border-box}
html{scroll-behavior:smooth}
body{background:var(–bg);color:var(–ink);font-family:var(–sans);font-size:16px;line-height:1.85;
background-image:radial-gradient(1100px 460px at 70% -120px,rgba(106,166,255,.10),transparent 60%),
radial-gradient(900px 420px at 12% -80px,rgba(255,171,74,.08),transparent 60%);}
#bar{position:fixed;top:0;left:0;height:3px;width:0;z-index:99;
background:linear-gradient(90deg,var(–or),var(–te));border-radius:0 3px 3px 0}
.wrap{max-width:1120px;margin:0 auto;padding:0 24px}
.grid{display:grid;grid-template-columns:216px minmax(0,1fr);gap:52px}
/* ———- TOC ———- */
nav.toc{position:sticky;top:36px;align-self:start;padding-top:8px}
nav.toc .toc-t{font-family:var(–mono);font-size:11px;letter-spacing:.22em;color:var(–dim);margin-bottom:14px}
nav.toc a{display:block;color:var(–mut);text-decoration:none;font-size:13.5px;line-height:1.5;
padding:5px 10px;border-left:2px solid var(–line);transition:.18s}
nav.toc a:hover{color:var(–ink)}
nav.toc a.on{color:var(–or);border-left-color:var(–or);background:linear-gradient(90deg,rgba(255,171,74,.08),transparent)}
@media (max-width:1080px){.grid{grid-template-columns:1fr}nav.toc{display:none}}
/* ———- hero ———- */
header.hero{padding:76px 0 46px}
.kicker{font-family:var(–mono);font-size:12.5px;letter-spacing:.18em;color:var(–te);margin-bottom:18px}
h1{font-size:clamp(30px,4.6vw,46px);line-height:1.28;font-weight:800;letter-spacing:.01em}
h1 .hl{background:linear-gradient(92deg,var(–or),var(–ye) 55%,var(–te));
-webkit-background-clip:text;background-clip:text;color:transparent}
.sub{margin-top:18px;max-width:680px;color:var(–mut);font-size:17px}
.badges{display:flex;flex-wrap:wrap;gap:10px;margin-top:26px}
.badge{font-family:var(–mono);font-size:12px;color:var(–mut);border:1px solid var(–line);
background:var(–card);border-radius:999px;padding:5px 14px}
.badge b{color:var(–ink);font-weight:600}
/* ———- sections ———- */
main section{padding:34px 0 10px;scroll-margin-top:24px}
.shead{display:flex;align-items:center;gap:14px;margin-bottom:6px}
.chip{font-family:var(–mono);font-size:12px;font-weight:700;color:#0b1020;border-radius:8px;padding:3px 9px;flex:none}
h2{font-size:25px;font-weight:750;letter-spacing:.01em;line-height:1.4}
h3{font-size:17.5px;font-weight:700;margin:26px 0 4px}
p{margin:14px 0;color:#d7deec}
p.lead{font-size:17px}
.mut{color:var(–mut)}
strong{color:var(–ink)}
a.lnk{color:var(–te);text-decoration:none;border-bottom:1px dashed rgba(61,219,196,.45)}
a.lnk:hover{color:#7deedb}
.anchor{color:var(–dim);font-size:.8em;text-decoration:none;margin-left:6px;opacity:0;transition:.15s}
h2:hover .anchor{opacity:1}
.c1{background:var(–or)}.c2{background:var(–te)}.c3{background:var(–bl)}
.c4{background:var(–pu)}.c5{background:var(–ye)}.c6{background:var(–rd)}
.c7{background:#8fd3ff}.c8{background:#ffa8c5}.c9{background:#9ef07a}.c10{background:#f2b8ff}
/* ———- callouts ———- */
.box{border-radius:14px;padding:18px 20px 16px;margin:22px 0;border:1px solid var(–line);
background:var(–card);position:relative}
.box .bt{font-family:var(–mono);font-size:11.5px;letter-spacing:.2em;margin-bottom:8px;font-weight:700}
.box p{margin:8px 0}
.box.analogy{border-left:3px solid var(–te)}
.box.analogy .bt{color:var(–te)}
.box.try{border-left:3px solid var(–or)}
.box.try .bt{color:var(–or)}
.box.warn{border-left:3px solid var(–rd);background:linear-gradient(180deg,rgba(255,107,122,.07),var(–card))}
.box.warn .bt{color:var(–rd)}
.box.edge{border-left:3px solid var(–ye)}
.box.edge .bt{color:var(–ye)}
/* ———- code ———- */
figure.code{margin:22px 0;border:1px solid var(–line);border-radius:14px;overflow:hidden;background:var(–panel)}
.code header{display:flex;align-items:center;gap:10px;padding:9px 16px;background:rgba(255,255,255,.025);
border-bottom:1px solid var(–line)}
.code header .dot{width:9px;height:9px;border-radius:50%;background:var(–line)}
.code header .lang{font-family:var(–mono);font-size:11.5px;letter-spacing:.14em;color:var(–dim)}
.code header .cap{font-size:12px;color:var(–mut);margin-left:auto;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.code .copy{font-family:var(–mono);font-size:11px;color:var(–mut);background:transparent;
border:1px solid var(–line);border-radius:7px;padding:2px 10px;cursor:pointer;flex:none;transition:.15s}
.code .copy:hover{color:var(–ink);border-color:var(–dim)}
pre{padding:16px 18px;overflow-x:auto;font-family:var(–mono);font-size:13.5px;line-height:1.75;color:#dbe4f5}
code .c-com{color:#6d7f9f;font-style:italic}
code .c-str{color:#ffd08a}
code .c-kw{color:#8ab8ff}
code .c-cmd{color:#ffb26b;font-weight:600}
code .c-flag{color:#9f8fff}
/* ———- terminal mockup ———- */
.term{border:1px solid var(–line);border-radius:14px;overflow:hidden;margin:22px 0;background:#070b16}
.term header{display:flex;gap:7px;padding:11px 14px;background:rgba(255,255,255,.03);border-bottom:1px solid var(–line)}
.term header i{width:11px;height:11px;border-radius:50%}
.term header i:nth-child(1){background:#ff5f57}.term header i:nth-child(2){background:#febc2e}.term header i:nth-child(3){background:#28c840}
.term .ttitle{font-family:var(–mono);font-size:11.5px;color:var(–dim);margin-left:8px}
.term pre{padding:16px 18px}
.t-p{color:var(–te)}.t-c{color:#dbe4f5}.t-out{color:#8d9cb8}.t-ok{color:#9ef07a}.t-me{color:var(–or)}
/* ———- svg figure ———- */
figure.diagram{margin:26px 0;padding:20px 12px 8px;border:1px solid var(–line);border-radius:14px;background:var(–card)}
figure.diagram svg{width:100%;height:auto;display:block}
figure.diagram figcaption{text-align:center;font-size:12.5px;color:var(–dim);padding:10px 0 8px}
/* ———- lists & tables ———- */
ul,ol{margin:14px 0 14px 4px;list-style:none}
ul li,ol li{padding-left:26px;position:relative;margin:9px 0;color:#d7deec}
ul li::before{content:””;position:absolute;left:6px;top:.72em;width:7px;height:7px;border-radius:2px;background:var(–te);transform:rotate(45deg)}
ol{counter-reset:step}
ol li::before{counter-increment:step;content:counter(step);position:absolute;left:0;top:.32em;
font-family:var(–mono);font-size:11px;font-weight:700;color:var(–or);
border:1px solid rgba(255,171,74,.4);border-radius:7px;width:19px;height:19px;line-height:17px;text-align:center}
table{width:100%;border-collapse:collapse;margin:22px 0;font-size:14px}
th{font-family:var(–mono);font-size:11px;letter-spacing:.16em;color:var(–dim);text-align:left;
padding:10px 14px;border-bottom:1px solid var(–line)}
td{padding:11px 14px;border-bottom:1px solid rgba(34,48,80,.55);vertical-align:top;color:#d7deec}
tr td:first-child{font-family:var(–mono);font-size:12.5px;color:var(–or);white-space:nowrap}
td .d{color:var(–mut)}
hr.sep{border:none;height:1px;background:linear-gradient(90deg,transparent,var(–line),transparent);margin:26px 0}
/* ———- footer ———- */
footer{margin-top:60px;padding:36px 0 60px;border-top:1px solid var(–line)}
footer p{color:var(–dim);font-size:13px;margin:6px 0}
footer a{color:var(–mut);text-decoration:none;border-bottom:1px dashed var(–line)}
footer a:hover{color:var(–te)}
.codeinline{font-family:var(–mono);font-size:.86em;color:var(–ye);background:rgba(255,216,77,.08);
border:1px solid rgba(255,216,77,.16);border-radius:6px;padding:1.5px 7px;white-space:nowrap}
code.plain{font-family:var(–mono);font-size:.88em;color:#bfe3ff;background:rgba(106,166,255,.09);border-radius:5px;padding:1px 6px}
QUICKSTART · PRIMEINTELLECT-AI / PRIME-AGENT
Prime Agent 快速入门: 给模型一个 REPL ,不是一堆按钮
一个开源编码与研究代理的上手指南——上下文可以当变量摆弄,子代理可以像函数一样调用,经验可以存在对话外面。装好大概五分钟;跑通第一晚,大概一个晚上。
MIT 开源
20k+ GitHub stars
arXiv:2608.23552
macOS · Linux · Windows (Git Bash)
2026-09-07 编写
目录
一个你见过的场面
它赌了什么
RLM:两个核心句
会写批注的助手
五分钟上手
第一晚怎么玩
让它活过一晚
教它记住
速查表
容易懵的三个点
你让 AI 修一个 bug。前十轮很顺。第三十轮,它开始重复问你早就回答过的问题。第四十轮,它把刚修好的代码改了回去,还理直气壮。
模型没有变笨。是工作台满了。
上下文窗口就是模型的工作台。对话越长,台面上堆的东西越多;放不下的就被收走——压缩成摘要,或者干脆截断。收走的那些,模型就真的不知道了。这不算事故,这是设计:注意力有限,人也是。
2026 年,几乎每个团队都在做自己的 agent。Prime Intellect——做去中心化训练、INTELLECT 系列模型、Verifiers 的那家——把他们的答案开源了,叫 Prime Agent 。MIT 协议,GitHub 上两万颗星,还配了篇论文(arXiv:2608.23552)。它同时是两样东西:一个今天就能干活的编码 agent,和一次关于「agent 该怎么搭」的公开下注。
这篇教程带你把它跑起来,搞清楚它赌的是什么,然后扔给它一个真实的活儿。
先去掉名字看本质。Prime Agent 的全部新意压在两个想法上。
想法一:别给模型一排按钮,给它一门语言
大多数 agent 给模型一排工具按钮:读文件按一个,跑命令按一个,搜索再按一个,模型在面板前按来按去。Prime Agent 只给一个内置工具——一个持久活着的 Python 会话 (ipython 内核)。读文件、跑测试、搜代码、调技能、派助手,全部写成 Python 代码。按钮面板换成了一门语言。
想法二:把经验存在对话外面
第二个抽象叫 Continual Harness (持续挽具)。补充提示、记忆、技能描述、子代理规格,都作为可持久化的状态存在;agent 干完活可以复盘,对它们做小的、有证据的修改。底座系统提示永远不可改,每笔修改带快照,随时回滚。
一个管「怎么干活」,一个管「怎么越干越好」。剩下的都是细节,我们一个个来。
RLM,Recursive Language Model,递归语言模型。名字挺唬人,拆开就两句话。
第一句:上下文即变量 (prompt-as-a-variable)。平常,上下文是一坨必须整个塞进模型注意力的文本。Prime Agent 里,上下文是内核里的一个变量——模型可以 print() 它、切片它、搜索它,把没用的部分扔掉,只把要紧的几行送进注意力。
类比
你不需要背下整本书才叫读过它。你需要的是一副能翻页的手。
第二句:子代理即函数调用 。在内核里:
PYTHON 内核里预装了 rlm,直接调用 复制
review = await rlm("审查认证流程的安全问题", name="auth-reviewer")
这一行派出去的是一个完整的 agent ——有自己独立的上下文和会话目录,继承父代理的模型、工具、技能。三个细节,都是新手容易懵的地方:
它返回的不是答案,是受理回执。 回执(handle)里有孩子的 id、名字、会话目录。答案要等孩子干完活,用消息寄回来,或者写进文件。
并行是白送的。 连发三个 rlm(),结束本轮,三个孩子同时开跑。
默认递归深度是一层。 根代理能生孩子,孙子默认不行——要更深的递归得改配置。
Python 调用
受理回执
agent_message 回信
任务 + 上下文
你的那句话
父代理(模型)
注意力留给要紧的事
Python 内核
持久 REPL
变量跨轮存活
文件 · 数据 · shell
bash() 跑项目命令
技能 = import 的包
await skill_fn(…)
rlm(…) 子代理 ×N
独立上下文 · 并行跑
答案 / 下一轮
该压的压,该留的留
RLM 循环:模型用 Python 调用一切,子代理用消息回信(示意)
类比在哪里失效
RLM 不改变模型本身——模型还是那个模型,智商没涨。它改的是模型周围的执行环境。区别不在「换了颗更聪明的大脑」,而在「一个只有好记性的人」与「一个带着笔记本、电话和三个助手的人」之间。
Continual Harness 解决另一个问题:agent 每次上班都像新人。
/refine 命令让 agent 回顾刚才的轨迹,把学到的教训写成小的、可审查的更新——一条补充提示、一条记忆、一个技能描述、一份子代理规格——存进会话状态。下次遇到类似的活儿,带着经验直接上。
规矩很严:底座系统提示是宪法,永远不改;所有修改写进笔记本,每一笔有记录、有快照,随时撕掉重来。
边界
它不会因此变成天才。它只是不再重复交同一笔学费。
macOS 或 Linux,一行装好:
BASH 官方安装脚本 复制
curl -fsSL https://app.primeintellect.ai/prime-agent/install.sh | sh
想尝鲜 main 分支的 beta 版,把结尾改成 | sh -s -- beta。安装器会下载版本化发布包、校验 SHA-256、装好 prime-agent 命令,并准备 agent 要用的 Python 运行时。Windows 也能跑:它需要一个 bash,装个 Git for Windows 就够。
动手
cd 到你的项目目录,启动,第一次运行 /login 选提供商:
BASH 启动 复制
cd /path/to/project
prime-agent
订阅直接用:Claude Pro/Max、ChatGPT Plus/Pro(Codex)、GitHub Copilot 都在内置列表里。不想用订阅,也可以先 export ANTHROPIC_API_KEY=sk-ant-... 再启动,或在 /login 里选 API-key 提供商——钥匙存进 ~/.prime/agent/auth.json。
源码党:Node.js ≥ 22.8.0,git clone → npm ci → ./prime-agent.sh。
丑话说在前面
Prime Agent 以你的用户权限 执行模型生成的 Python 和项目命令。它的 worker / kernel 进程做的是进程隔离——为了崩溃恢复,不是为了安全。它不是沙箱。
对策也便宜:用一次性 clone 或干净的 git worktree;别在堆满密钥的目录里放它出来;跑不受信代码,扔到外部沙箱里去。
进去之后长这样(示意图,细节随版本变):
prime-agent · ~/my-project
› /login
选择提供商:Claude Pro/Max · ChatGPT (Codex) · GitHub Copilot · API Key…
✓ 已登录
› Summarize this repository and tell me how to run its checks.
✓ 内核已启动 · 扫描仓库 · bash("npm run check")
这是一个 … 的仓库。检查用 npm run check 跑,当前 … 项通过。
然后按顺序玩这五样,一个晚上足够建立手感:
甩文件给它。 输入框里打 @ 模糊搜索项目文件;或者命令行直接 prime-agent @src /app.ts "Review this"。截图 Ctrl+V 直接贴进去。
替它跑命令。 !npm run lint ——输出送给模型看;!!command ——只给你自己看,不进模型上下文。
派一次子代理。 直接说人话:「把认证审查和测试覆盖当成两个独立子任务,并行跑,最后汇总。」然后看它在内核里连发两个 rlm()。
给它立规矩。 项目根目录放一个 AGENTS.md(见下),改完 /reload 生效。全局规矩放 ~/.prime/agent/AGENTS.md。
问完就走。 prime-agent -p "Summarize this codebase" ——一次性模式,答完退出,适合嵌进脚本。
AGENTS.MD 项目守则示例 复制
# 项目守则
- 改完代码必须跑 `npm run check`。
- 别在本地跑生产库迁移。
- 回答保持简短,先给结论。
顺手的旋钮:换模型 /model 或 Ctrl+L;思考深度 /effort;会话自动存在 ~/.prime/agent/sessions/,prime-agent -c 接着上次聊。
这是 Prime Agent 跟「终端里的小玩具」拉开差距的地方:关掉终端,它不下班。
普通会话跑在常驻 worker 进程里。关窗口只是离开工位,工人还在工地:
BASH 后台会话三件套 复制
prime-agent agents # 看谁还在干活
prime-agent attach <agent> # 重新接上去
prime-agent shutdown # 全部收工(真下班时用)
再往上,是几个长寿开关:
/goal :立一个持续目标,跨轮次有效,直到完成、暂停或你手动清除。/goal status 看进度。
/heartbeat :定时回到当前会话干活。/heartbeat every 10m 检查部署状态,有变化就报告。
prime-agent schedule :一次性或 cron 周期任务,UI 关着照样触发。
/autonomous :有边界的自动驾驶。配「质量门」(gate)——门不过就继续修,门过了才准收工;轮数、token、时长都有上限。
BASH 带质量门的自动驾驶 复制
prime-agent --autonomous
--autonomous-gate "npm run check"
--autonomous-max-turns 20
"实现这个改动,并验证检查通过"
上下文太长怎么办?自动压缩(compaction):旧对话被摘要,Python 内核原样活着 ——变量、导入、解析到一半的数据都在。真正重要的东西,请落在文件里、变量里,或者用 /refine 写进记忆。「对话」是这个地方最不适合存东西的地方。
三层记忆,从硬到软:
AGENTS.md :项目规矩。你写,它读,每次启动加载。跟 CLAUDE.md 通用。
Skills(技能包) :普通技能是一份 SKILL.md,说明书写给模型看;Python 技能更进一步——一个真正 import 进内核的包,模型直接 await release_audit(repository=".", target_version="0.4.0")。内置的 skill-creator 能把你们重复干过的流程变成技能。
/refine :agent 自己写的笔记本。小的、有证据的、可回滚的。
用法忠告
先让 AGENTS.md 承担规矩,让技能承担流程,最后才轮到 /refine 承担零碎教训。顺序反过来,你会得到一本没人审的流水账。
终端命令 干什么
prime-agent 在项目目录里启动交互会话
prime-agent -c 接着最近一次会话聊
prime-agent -p “…” 一次性提问,答完退出(可接管道输入)
prime-agent agents / attach 看还在跑的会话 / 重新接上
prime-agent schedule add … 定时或 cron 周期任务
prime-agent doctor –fix 后台服务出毛病时,体检加修理
prime-agent shutdown 停掉所有 agent、worker 与后台服务
会话内命令 干什么
/login · /model · /effort 登录 · 换模型 · 调思考深度
/goal · /heartbeat · /autonomous 立目标 · 定时回访 · 有边界自动驾驶
/refine · /compact 复盘攒经验 · 手动压缩上下文
/resume · /new · /fork · /tree 会话管理:回到任意历史点继续
/export · /share 导出 HTML / 私有 gist 分享
@file · !cmd · !!cmd 引用文件 · 跑命令给模型看 · 只给自己看
rlm() 的返回值不是答案。 返回值是受理回执。答案走 agent_message 或文件。第一次用,以为返回值就是结果,会等出一个寂寞。
质量门通过 ≠ 任务成功。 官方自己的措辞很诚实:一个通过的门只验证它检查的东西;限额到顶停下,也不代表干完了。gate 写得越接近「你真实的验收标准」,自动驾驶才越可信。
摘要会吃掉对话细节。 压缩保内核,不保聊天记录。重要的结论让它写文件、写记忆,别让它在对话里「记一下」。
还有个态度问题:「self-improving」到底能攒出多少真本事,论文和数据都是它自己给的。最好的办法跟验证任何实验一样——拿你自己的仓库,跑一个晚上,看数据。
Prime Agent 下注的方向是:agent 的下一步不在「更大的窗口」,而在「更好的工作台」——上下文可以被程序摆弄,助手可以像函数一样被调用,经验可以存在对话外面。
这个赌注对不对,吵不出结果。装一个,扔个真实任务给它过夜,第二天早上看台面上留下了什么。
就这么回事。
参考与延伸(撰写于 2026-09-07,命令以官方文档为准):
GitHub · PrimeIntellect-ai/prime-agent ·
Quickstart 文档 ·
RLM 编程模型 ·
RLM 博客 ·
论文 arXiv:2608.23552 ·
Continual Harness arXiv:2605.09998
Prime Agent 基于开源项目 pi 构建,MIT 许可发行。本文为独立教程,与 Prime Intellect 无关;示意图为简化示意,以官方文档为准。
(function(){
“use strict”;
var esc=function(t){return t.replace(/&/g,”&”).replace(//g,”>”);};
var KW=/b(?:await|async|from|import|for|in|def|return|if|elif|else|not|and|or|None|True|False|class|with|as|while|try|except|print|list|next)b/y;
var RULES={
python:[
{re:/#[^n]*/y,cls:”c-com”},
{re:/(?:[frb])?”(?:[^”\n]|\.)*”|(?:[frb])?'(?:[^’\n]|\.)*’/y,cls:”c-str”},
{re:KW,cls:”c-kw”}
],
bash:[
{re:/(?:^|n)(s*)#[^n]*/y,cls:”c-com”,skip:1},
{re:/”(?:[^”\n]|\.)*”|'[^’n]*’/y,cls:”c-str”},
{re:/ +#[^n]*/y,cls:”c-com”},
{re:/(?:^|n)s*(?:sudos+)?(?:curl|cd|export|git|npm|npx|cat|sh|bash|prime-agent|node)b/y,cls:”c-cmd”,lead:1},
{re:/s–?[a-zA-Z][w-]*/y,cls:”c-flag”}
],
markdown:[
{re:/^#[^n]*/y,cls:”c-cmd”,lead:1},
{re:/^[-*] /y,cls:”c-flag”},
{re:/`[^`n]*`/y,cls:”c-str”}
],
text:[]
};
function tokenize(src,lang){
var rules=RULES[lang]||RULES.text,out=””,i=0,m,r,j,hit;
while(i<src.length){
hit=false;
for(j=0;j<rules.length;j++){
r=rules[j]; r.re.lastIndex=i; m=r.re.exec(src);
if(m&&m.index===i&&m[0].length){
if(r.skip){out+=esc(m[1]||"");out+='
‘+esc(m[0].slice((m[1]||””).length))+” “;}
else if(r.lead){var w=m[0].replace(/^(n?[s]*)(.*?)(s*)
1″),rest=m[0].slice(w.length);
out+=esc(w)+’
‘+esc(rest)+” “;}
else{out+=’
‘+esc(m[0])+” “;}
i+=m[0].length;hit=true;break;
}
}
if(hit)continue;
out+=esc(src[i]);i++;
}
return out;
}
document.querySelectorAll(“figure.code”).forEach(function(f){
var code=f.querySelector(“code”);
code.innerHTML=tokenize(code.textContent,f.dataset.lang||”text”);
var btn=f.querySelector(“.copy”);
if(btn)btn.addEventListener(“click”,function(){
var txt=code.textContent,done=function(){btn.textContent=”已复制 ✓”;setTimeout(function(){btn.textContent=”复制”;},1400);};
if(navigator.clipboard&&navigator.clipboard.writeText){navigator.clipboard.writeText(txt).then(done).catch(function(){fallback(txt);done();});}
else{fallback(txt);done();}
});
function fallback(t){var ta=document.createElement(“textarea”);ta.value=t;ta.style.position=”fixed”;ta.style.opacity=”0″;document.body.appendChild(ta);ta.select();try{document.execCommand(“copy”);}catch(e){}document.body.removeChild(ta);}
});
var links=[].slice.call(document.querySelectorAll(“nav.toc a”));
var map={};links.forEach(function(a){map[a.getAttribute(“href”).slice(1)]=a;});
if(“IntersectionObserver” in window){
var io=new IntersectionObserver(function(es){
es.forEach(function(e){
if(e.isIntersecting){links.forEach(function(l){l.classList.remove(“on”);});var l=map[e.target.id];if(l)l.classList.add(“on”);}
});
},{rootMargin:”-15% 0px -70% 0px”});
[].slice.call(document.querySelectorAll(“main section[id]”)).forEach(function(s){io.observe(s);});
}
var bar=document.getElementById(“bar”);
addEventListener(“scroll”,function(){
var h=document.documentElement;
bar.style.width=(h.scrollTop/(h.scrollHeight-h.clientHeight)*100)+”%”;
},{passive:true});
})();