[2026.03 Week 3] Five Trending Repos of the Week
Five GitHub repositories trending this week.
Paperclip (⭐ 31.2k). AI agents that run business ops autonomously: issue triage to deployment.
DeepAgents (⭐ 16.3k). LangGraph harness that spawns subagents with isolated context windows.
Crucix (⭐ 6k). Monitors 27 data sources and alerts you when something changes.
Page Agent (⭐ 13k). Browser agent that controls web UIs with natural language.
Open SWE (⭐ 7.9k). Open-source SWE agent that runs in a sandbox and stays responsive to new instructions.
paperclipai/paperclip
⭐ 31.2k · TypeScript
Running a company’s ops with AI agents requires coordinating task routing, agent spawning, and budget enforcement across parallel workers. Paperclip is an orchestration platform built for this.
Multiple workers polling the same task queue will inevitably race to grab the same job. Paperclip skips external locks entirely. Instead, the claim is a conditional UPDATE that only succeeds if the row hasn’t already been taken.
paperclipai/paperclip:server/src/services/heartbeat.ts:L1349-L1382
async function claimQueuedRun(run: typeof heartbeatRuns.$inferSelect) {
if (run.status !== "queued") return run;
const agent = await getAgent(run.agentId);
if (!agent) {
await cancelRunInternal(run.id, "Cancelled because the agent no longer exists");
return null;
}
// ...
const budgetBlock = await budgets.getInvocationBlock(run.companyId, run.agentId, {
issueId: readNonEmptyString(context.issueId),
projectId: readNonEmptyString(context.projectId),
});
if (budgetBlock) {
await cancelRunInternal(run.id, budgetBlock.reason);
return null;
}
const claimedAt = new Date();
const claimed = await db
.update(heartbeatRuns)
.set({ status: "running", startedAt: run.startedAt ?? claimedAt, updatedAt: claimedAt })
.where(and(eq(heartbeatRuns.id, run.id), eq(heartbeatRuns.status, "queued")))
.returning()
.then((rows) => rows[0] ?? null);
if (!claimed) return null;The WHERE clause checks both the run ID and that the status is still "queued". If two workers race to claim the same task, the loser’s update affects zero rows and returning() yields nothing. Budget enforcement happens before the claim, so agents that exceed their token allowance never start.
langchain-ai/deepagents
⭐ 16.3k · Python
Complex tasks often need to be broken into subtasks and delegated to specialized agents. DeepAgents is LangChain’s harness for this, with a planning tool, a filesystem backend, and subagent spawning.
When a parent agent spawns a child, the child should only see what it needs. If the parent’s full message history, todos, and memory leak through, the child hallucinates off irrelevant context and burns tokens on noise.
langchain-ai/deepagents:libs/deepagents/deepagents/middleware/subagents.py:L115-L127
# State keys that are excluded when passing state to subagents
# and when returning updates from subagents.
# ...
# The skills_metadata and memory_contents keys are automatically excluded from
# subagent output via PrivateStateAttr annotations. However, they must ALSO be
# explicitly filtered from runtime.state when invoking a subagent to prevent
# parent state from leaking to child agents.
_EXCLUDED_STATE_KEYS = {
"messages", "todos", "structured_response", "skills_metadata", "memory_contents"
}
def _validate_and_prepare_state(subagent_type, description, runtime):
subagent = subagent_graphs[subagent_type]
subagent_state = {k: v for k, v in runtime.state.items() if k not in _EXCLUDED_STATE_KEYS}
subagent_state["messages"] = [HumanMessage(content=description)]
return subagent, subagent_stateEach subagent starts with a clean message history containing only its task description. The parent’s accumulated messages, todos, and memory are stripped out. The comment explains why the filtering is needed even though PrivateStateAttr already hides some keys from output: the annotations prevent leaks in one direction, but you still need explicit filtering on the way in.
calesthio/Crucix
⭐ 6k · JavaScript
Keeping track of changes across dozens of data sources without drowning in duplicate alerts is surprisingly hard. Crucix is a personal intelligence agent that pulls from 27 sources (Telegram channels, RSS feeds, government APIs) on a 15-minute cycle and alerts you when something meaningful changes.
The hard part is deduplication. Different sources report the same event with different wording, timestamps, and numbers. “BREAKING: 5 missiles at 14:32” and “Breaking: 7 missiles at 15:01” are the same alert. The contentHash function handles this with aggressive normalization before hashing.
calesthio/Crucix:lib/delta/engine.mjs:L73-L84
function contentHash(text) {
if (!text) return '';
const normalized = text
.toLowerCase()
.replace(/\d{1,2}:\d{2}(:\d{2})?/g, '') // strip times
.replace(/\d+/g, 'N') // normalize all numbers
.replace(/[^\w\s]/g, '') // strip punctuation
.replace(/\s+/g, ' ')
.trim()
.substring(0, 100);
return createHash('sha256').update(normalized).digest('hex').substring(0, 12);
}Times get stripped, numbers become N, punctuation disappears. The two headlines from the example above produce the same hash after normalization. The 100-character truncation and 12-hex-character output keep the hash table small while still providing enough entropy to avoid false collisions in practice.
alibaba/page-agent
⭐ 13k · TypeScript
Browser automation tools like Playwright and WebDriver run outside the page, requiring external processes and protocol overhead. Page Agent takes a different approach: a JavaScript agent that runs inside the browser page itself and translates natural language instructions into DOM interactions.
A button can exist in the DOM but be completely hidden behind a modal, a sticky header, or an overlay. querySelector will find it, but a user can’t click it. Page Agent needs to tell the difference, and the visibility check is less obvious than you’d expect.
alibaba/page-agent:packages/page-controller/src/dom/dom_tree/index.js:L1041-L1064
const checkPoints = [
// Initially only this was used, but it was not enough
{ x: rect.left + rect.width / 2, y: rect.top + rect.height / 2 },
{ x: rect.left + margin, y: rect.top + margin }, // top left
// { x: rect.right - margin, y: rect.top + margin }, // top right
// { x: rect.left + margin, y: rect.bottom - margin }, // bottom left
{ x: rect.right - margin, y: rect.bottom - margin }, // bottom right
]
return checkPoints.some(({ x, y }) => {
try {
const topEl = document.elementFromPoint(x, y)
if (!topEl) return false
let current = topEl
while (current && current !== document.documentElement) {
if (current === element) return true
current = current.parentElement
}
return false
} catch (e) {
return true
}
})The browser’s elementFromPoint API returns whatever is visually on top at a given coordinate. The code probes three points (center, top-left, bottom-right) and walks up the DOM tree from each hit to see if the target element is an ancestor. The commented-out top-right and bottom-left checks were disabled after testing showed diminishing returns. The catch returns true on error, which is intentionally permissive: better to include a false positive than to hide a valid interactive element from the agent.
langchain-ai/open-swe
⭐ 7.9k · Python
Most coding agents run synchronously: you give instructions, wait, then give more. Open SWE is an asynchronous coding agent from the LangChain team that accepts follow-up instructions mid-task, works inside a sandboxed environment, files pull requests, and posts updates to Linear and Slack.
You can post follow-up comments on a Linear issue while the agent is still working. The middleware that makes this possible is small.
langchain-ai/open-swe:agent/middleware/check_message_queue.py:L79-L97
namespace = ("queue", thread_id)
try:
queued_item = await store.aget(namespace, "pending_messages")
except Exception as e:
logger.warning("Failed to get queued item: %s", e)
return None
if queued_item is None:
return None
queued_value = queued_item.value
queued_messages = queued_value.get("messages", [])
# Delete early to prevent duplicate processing if middleware runs again
await store.adelete(namespace, "pending_messages")
if not queued_messages:
return NoneThis runs as a @before_model middleware, meaning it fires before every LLM call. If someone posts a follow-up comment on a Linear issue while the agent is mid-task, that comment lands in the queue via LangGraph’s store. The middleware picks it up, deletes it immediately to prevent double-processing, and injects it as a new human message. The agent sees the updated instructions on its next turn without restarting the entire run.

