#喜欢的音乐 #博客更新
棒无的碎碎念,在,漫长岁月里
Cohub 实操:用一个 Space 从零搭一个可发布的小工具
#博客更新

disclosure:这是我们公司(Viscept)做的产品,这篇是实操向,我会讲清楚每一步在干什么、有什么坑。

先说结论

如果你想试 Cohub,最快的入门路径不是看文档,而是走一遍真实的闭环
创建一个 Space → 和 Agent 说需求 → 它建文件/装依赖/跑起来 → Save 存 Checkpoint → 发布成 Work

整个过程大概 20 分钟。这篇文章记录我实际跑通的步骤,包括遇到的坑。

第一步:创建 Space

Cohub 的核心单元是 Space。你可以把它理解成「一个隔离的开发环境 + 对话 + 文件系统 + Agent」。

用 CLI 创建(cohub 是官方 CLI):
# 安装(如果你还没有)
npm install -g @neta-art/cohub-cli

# 登录
cohub auth login

# 列出你的 spaces
cohub spaces ls

# 创建新 space
cohub spaces create --name "my-first-tool"

或者直接在 web 上点 New Space 也行。我建议至少 CLI 装一个,因为后面很多操作 CLI 更快。

第二步:和 Agent 提需求

创建之后,打开 Space,跟 Agent 说你要做什么。关键是要把需求讲清楚,就像跟一个工程师同事提需求:
帮我做一个 Markdown 转 HTML 的小工具,输入一段 markdown,输出渲染后的 HTML。要能选样式主题,还要有一个预览区域。
注意几个点:

1. 说目标,不说实现。不需要告诉它用什么库,它会自己选。
2. 一次一个需求。第一轮先让它把核心功能做出来,再迭代加功能。
3. 它可以读写文件、跑命令。Agent 不是只回复文本,它会在 Space 的文件系统里创建文件、装依赖、跑 dev server。

第三步:看它干活,必要时纠偏

Agent 开始干活后,你会看到它:

创建项目文件(package.json、源码等)
npm install 装依赖
启动 dev server,暴露预览端口

这里有个经验:Agent 第一次做出来的东西,大概率不是你要的最终版。正常的迭代节奏是:
第一轮:核心功能能用
第二轮:你试了,提反馈("样式太丑""这个按钮没反应")
第三轮:它改,你再试

在 Cohub 里,你可以在同一个 Space 的预览区直接试它做出来的东西,不用自己本地跑。这个循环比「聊天里来回贴代码」高效得多。

第四步:Save(Checkpoint)

当你对当前状态满意(或者到了一个里程碑),存一个 Checkpoint:
cohub -s <space-id> spaces checkpoints create --message "markdown-to-html v1 done"

为什么这个重要:

1. 它是不可变快照。之后再怎么改,都能回到这个点。
2. 可以 fork。从这个 Checkpoint 分支出新想法,不影响主线。
3. 是可分享的稳定基底。别人可以基于你的 Checkpoint 继续工作。

这比 git commit 更像「存档」——你随时能回到任何有意义的时刻。

第五步:发布成 Work

这是 Cohub 和大多数 AI 工具最大的区别:Agent 的产出可以直接发布成一个公开可访问的页面(Work)
# 把项目构建成静态文件后发布
cohub -s <space-id> spaces files ls

# 发布目录为 Work
cohub -s <space-id> works publish my-tool --file dist/index.html

发布后你会得到一个公开 URL,任何人打开就能用你做的工具。这个 Work 还可以:

配置访问权限
用 Work Commerce 变现(卖功能解锁/积分)
被 fork 和 remix

实际遇到的坑

坑 1:Agent 装依赖慢

第一次让 Agent 跑 npm install,如果网络慢会等很久。解决办法:让它用国内镜像,或者先用最简依赖把核心跑通,再逐步加。

坑 2:端口预览 vs 实际发布

开发时 Agent 起的 dev server 端口,和发布后的静态托管不是一回事。如果你做的是 SPA 或需要后端的应用,发布时要注意:

纯前端 → 构建后发布 dist/ 即可
需要后端 → 用 Cohub 的 Sandbox 能力或对外部 API

坑 3:迭代时别丢上下文

每轮给 Agent 反馈时,引用具体现象("点击提交后没反应")而不是模糊的("好像不太对")。Agent 在同一 Space 里有完整上下文,具体反馈能让它精准修改。

写在最后

Cohub 最有意思的地方,是把「和 AI 协作做东西」从聊天里搬到了一个有文件、有环境、能发布的真实空间里。

你可以把它当:

快速原型工具(几分钟做个工具验证想法)
一个带 Agent 的完整开发环境
一个内容/工具的分发平台(Work)

如果你还没试过,建议按这篇的流程走一遍。从"让 AI 聊天"到"让 AI 帮你把东西做出来并发布",这个转变,用了才知道。

----------------------

产品:cohub.run
CLI:npm install -g @neta-art/cohub-cli
生态索引:github.com/markbang/awesome-cohub

via 棒无
Docker 生产实践:从能跑到跑得稳的 Checklist
#博客更新

先说结论

「Docker 能跑」和「Docker 能稳定跑」是两回事。本地 docker run 一次成功,和在生产集群里扛住流量、重启、扩容,中间隔着不少坑。

这篇文章是我在生产环境踩过之后总结的 Checklist。不追求面面俱到,只讲高频、高影响的十件事,按重要程度排序。

1. 镜像尽量小,但要小得有理

镜像体积直接影响拉取时间和启动速度。常见手段:

alpinedistroless 作为基础镜像
● 多阶段构建:构建阶段用全量镜像,运行阶段只拷贝产物
清理不必要的缓存和包管理器元数据

# 多阶段构建示例
FROM node:20-alpine AS build
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build

FROM node:20-alpine
WORKDIR /app
COPY --from=build /app/dist ./dist
COPY --from=build /app/package*.json ./
RUN npm ci --omit=dev
EXPOSE 3000
CMD ["node", "dist/index.js"]

但注意:不是越瘦越好。distroless 没有 shell,调试会很痛苦;alpine 的 musl libc 偶尔和依赖有兼容问题。先瘦到合理范围,别为了几十 MB 自找麻烦。

2. 非 root 用户运行

默认容器内是 root,这是安全大忌。一旦容器被攻破,攻击者就是 root 权限。
FROM node:20-alpine
# 创建非 root 用户
RUN addgroup -S app && adduser -S app -G app
USER app

大多数官方镜像现在都支持直接切用户。这一步成本极低,收益很高。

3. 健康检查必须配

没有健康检查,编排系统(K8s/Swarm)就不知道你的容器是不是真的活着。进程在不代表服务可用。
HEALTHCHECK --interval=30s --timeout=5s --start-period=10s --retries=3 \
  CMD wget -q -O - http://localhost:3000/healthz || exit 1

注意 start-period——给应用启动留时间,别一上来就被打回。

4. 日志打 stdout,别写文件

容器里的日志应该走 stdout/stderr,由编排系统收集,而不是写到容器内的文件。原因:

容器文件系统是临时的,重启就没了
你没法轻易拿到容器内的文件
云平台(CloudWatch、ELK、Loki)都从 stdout 收集

所以应用日志直接 console.log/print,别自己写日志文件轮转。

5. 资源限制,不是可选项

不设 --memory--cpus 限制,一个失控的容器能拖垮整个节点。
# docker-compose 或 k8s 里都要设
resources:
  limits:
    memory: 512M
    cpus: "0.5"
  reservations:
    memory: 256M

limits 一定要设,reservations 至少给一个合理值。这是生产环境第一道防线。

6. 环境变量和密钥,别硬编码

镜像里不要写死任何密钥。用:

环境变量(运行时注入)
Docker secrets / K8s secrets
专门的密钥管理(Vault、云厂商的 secrets manager)

镜像一旦构建就难以「撤销」里面硬编码的密钥。密钥泄露的补救成本远高于一开始就用环境变量。

7. 固定依赖版本,别用 latest

FROM node:20-alpine 里的 20 可能今天和明天解析到不同的小版本。生产环境要可复现

基础镜像用精确 tag(如 node:20.18.0-alpine
依赖锁文件(package-lock.json / poetry.lock)进镜像
有需要时用 digest 固定镜像

可复现 = 可回滚 = 可调试。

8. 处理僵尸进程和信号

容器作为 PID 1 时,要正确处理信号(SIGTERM)和孤儿进程。常见方案:

用带 PID 1 处理的运行时(如 tini
确保应用能优雅关闭(监听 SIGTERM,完成在途请求)

RUN apk add --no-cache tini
ENTRYPOINT ["/sbin/tini", "--"]
CMD ["node", "dist/index.js"]

不然 docker stop 会变成 kill -9,数据库写一半就没了。

9. 镜像构建也要考虑 .dockerignore

.dockerignore 能大幅减少构建上下文和镜像体积,避免把 node_modules.git、日志、临时文件打进去。
node_modules
.git
*.log
.tmp
dist

这也是多阶段构建里第一层就过滤掉的东西。

10. 一个容器一个职责

别在一个容器里跑 web + worker + cron。拆开:

各自独立扩缩容
一个挂了不影响其他
日志、健康检查、资源限制都更清晰

一个容器只做一件事,是容器化最大的架构收益。

验证清单

改完以后,跑一遍这个验证:
# 1. 镜像构建成功且体积合理
docker build -t my-app .

# 2. 容器能启动且健康检查通过
docker run -d --name test -p 3000:3000 my-app
docker inspect --format='{{.State.Health.Status}}' test
# 期望: healthy

# 3. 优雅停止
docker stop test
# 观察日志是否有优雅关闭记录

# 4. 资源限制生效
docker run --rm -m 256m my-app
# 期望: 超出限制时 OOM,而不是拖垮宿主


写在最后

这十条里,健康检查、资源限制、非 root、日志走 stdout 是成本最低、收益最高的四项,强烈建议从这些开始。

容器化不是终点,只是起点。把这些基础打牢,后面接 CI/CD、上 K8s 才会顺。

如果哪条你踩过不同的坑,欢迎交流。

via 棒无 Docker 生产实践:从能跑到跑得稳的 Checklist - 棒无
Copines - Aya Nakamura
#喜欢的音乐

歌手:Aya Nakamura
专辑:NAKAMURA
发行日期:11/1/2018

via 棒无喜欢的音乐 (author: Aya Nakamura)
马赛马拉迁徙的角马群横渡马拉河, 肯尼亚 (© Manoj Shah/Getty Images)

via Bing每日壁纸
天亮以前说再见 - 曲肖冰
#喜欢的音乐

歌手:曲肖冰
专辑:天亮以前说再见
发行日期:1/3/2019

via 棒无喜欢的音乐 (author: 曲肖冰)
非斯皇宫装饰华丽的大门,摩洛哥 (© cgst26/Shutterstock)

via Bing每日壁纸
佛罗里达穴鸮幼鸟,开普科拉尔,佛罗里达州,美国 (© mlorenzphotography/Getty Images)

via Bing每日壁纸
马尔萨什洛克港口五彩斑斓的渔船,马耳他 (© Klubovy/Getty Images)

via Bing每日壁纸
大批熔岩流涌入大洋,大岛,夏威夷州,美国 (© Ken McCurdy/Getty Images)

via Bing每日壁纸
手绘吱吱维

老头的成长轨迹

作者:流风云溯

via 一人之下吧
鸟瞰弗吉尼亚爬山虎步道,达马斯克斯,弗吉尼亚州,美国 (© Eifel Kreutz/Getty Images)

via Bing每日壁纸
在纳瓦霍族保留地的纪念碑谷,亚利桑那州,美国 (© Westend61/Adobe Stock)

via Bing每日壁纸
Back to Top