Vibecode Cluely
track this build4 phases, 12 steps, beginner friendly0%The core loop is genuinely thin: capture a screenshot, transcribe the mic, feed both to a multimodal model, stream the answer into a transparent always-on-top window on a hotkey. An agent gets that working in a session, and it will feel uncomfortably close to the demo. The gaps are the unglamorous parts: capturing the other side's audio takes virtual audio devices, latency has to beat the conversation, and the headline trick of staying invisible in screen shares depends on fragile platform window flags that vary by OS and conferencing app. Your DIY version will work fine when you are alone with your own screen, and may quietly betray you the one time it matters.
You are building a lean indie version of Cluely. Create the following project files first, then implement the application by following them. Keep the files updated as decisions change. Do not collapse this into a single README or prompt. ===== README.md ===== # Cluely · indie build A desktop assistant with access to what is on your screen and, with consent, what is said on your calls, where the engineering is in capturing selectively and locally, and the design is entirely about the capture being visible to everyone it affects. Estimated effort: **multi-day**. Work `BUILD_PLAN.md` top to bottom · every phase ends in a check that has to pass before the next one starts. ## Stack | Part | Choice | Why | | --- | --- | --- | | Capture | Screen region capture and system audio, each separately permitted | they are different intrusions and deserve different consent | | Processing | Local models by default, with any hosted call an explicit per-session choice | screen contents and call audio are the most sensitive things on a machine | | Indication | An always-visible indicator that cannot be disabled | the whole ethical position rests on the capture being apparent | | Retention | Short by default, with transcripts and screen text expiring separately | captured context loses value in minutes and stays sensitive for years | | Runtime | A native overlay application with a hotkey | it has to be reachable without leaving what you are doing | ## Before you start Have every one of these ready. The plan assumes them from step one. - [ ] **A machine whose capture permissions you understand** · free - Why: Screen and audio capture each need a system permission, and what each grants and how it is requested differs by platform and version. - Get it: Read your platform's current documentation for both permissions before designing the consent flow. - Verify: Both permissions can be requested separately and their state read - [ ] **A local model runner** · free, needs memory - Why: Screen contents and call transcripts are the most sensitive material on a machine and the default must not be sending them anywhere. - Get it: Any local runner with a model capable of answering from provided context. - Verify: A query answers from local context with networking disabled - [ ] **Your recording consent position** · free to read; an hour of advice if this is for work - Why: Capturing call audio records other people, and the rules attach to the recording rather than to the software being visible. - Get it: Identify where the people you call are, take the strictest applicable rule, and write down what you concluded. - Verify: A written note names the jurisdictions and the rule applied - [ ] **Your exclusion list, written before capture** · free - Why: A password manager, a private message window or a medical portal captured once is captured, and deciding the list afterwards is deciding it too late. - Get it: List applications and window title patterns that must never be captured. Err wide. - Verify: The list is loaded by the capture path before the first run - [ ] **A list of assessment and proctoring applications** · free - Why: Phase 3 refuses to operate in those contexts, and the check is only as good as the list. - Get it: Identify the proctoring and assessment tools in use where you are. Keep the list narrow so false positives stay rare, since there is no override. - Verify: A list exists and blocking is confirmed with at least one of them running ## Quick start Follow Phase 1 in `BUILD_PLAN.md`; it creates the project. Then copy `.env.example` to `.env` and fill in the values it documents. ## Honest limits This build deliberately does not replace: - Invisibility of any kind. - Use in interviews, exams and assessments. - Cloud storage of captures. - Real-time coaching during a live call. - Screen-share invisibility that has actually been tested against Zoom, Meet, Teams and OS screenshot tools - Sub-second latency and the prompt tuning that makes answers short enough to read while someone is talking - System audio capture that just works without you installing and routing a virtual audio device - Mobile and browser-extension coverage, plus a hosted account so your setup follows you to another machine - Somebody else's legal and PR exposure for a product whose pitch is 'cheat on everything' If one of those is essential to you, that is the reason to keep paying for Cluely, and the README should say so rather than pretend. ===== BRIEF.md ===== # Build brief · Cluely The one-shot brief this plan expands. `BUILD_PLAN.md` (or `MILESTONES.md`) is the same sequence broken into steps and checks; where the two disagree, the plan wins. Build me a desktop assistant that reads your screen and hears your calls, built to be disclosed to replace Cluely. Build it in phases, in the order below. Do not write the whole thing in one pass. Finish a phase, run its "Done when" check, fix what fails, and only then start the next phase. ### Rule zero This category is marketed around being invisible: an overlay that watches your screen and listens to your calls and feeds you answers, positioned for interviews, exams and sales calls where the other party does not know. Build the tool; do not build the invisibility. Two reasons, and neither is squeamishness. Undisclosed assistance in an interview or an assessment is misrepresentation, and it is the user who carries that, not the tool. And listening to a call means recording other people, which is governed by consent rules that attach to the recording regardless of whether anyone can see the software. So this build: has no screen-sharing evasion, no hidden-from-capture mode, no invisibility of any kind. It prompts to disclose when audio capture starts and records whether you did. It refuses to run in modes it can detect are assessments. Audio and screen capture are separately consented and separately indicated, with an indicator that cannot be turned off. The genuinely useful version of this is an assistant for your own work: your documents, your notes, your calls with consent. That version is worth building, and it is what follows. ### Stack (fixed, do not substitute) - Capture: Screen region capture and system audio, each separately permitted · they are different intrusions and deserve different consent - Processing: Local models by default, with any hosted call an explicit per-session choice · screen contents and call audio are the most sensitive things on a machine - Indication: An always-visible indicator that cannot be disabled · the whole ethical position rests on the capture being apparent - Retention: Short by default, with transcripts and screen text expiring separately · captured context loses value in minutes and stays sensitive for years - Runtime: A native overlay application with a hotkey · it has to be reachable without leaving what you are doing ### Data model (create this before Phase 1) - sessions(id, started_at, ended_at, screen_capture, audio_capture, disclosed_at, model_policy) - captures(id, session_id, kind, at, text, region_json, redacted) · kind is screen_text or transcript - exclusions(id, kind, pattern) · applications and window titles never captured, applied before writing - queries(id, session_id, prompt, response, model, at, capture_ids_json) · what context each answer used - consents(session_id, scope, granted_at, evidence) · screen and audio consented separately - assessment_blocks(id, detected_signal, at) · when the tool refused to run and why - A query records which captures it used, so you can always answer what the assistant saw when it said something. ### Phase 1 · Capture that announces itself Build: Screen and audio capture as separately requested permissions, each with its own visible indicator that cannot be hidden or disabled. Apply an exclusion list before writing anything. Make stopping capture immediate and obvious. Trap: Building an indicator that any setting can hide means the invisibility is one configuration change away, and the position that this tool is ethical rests entirely on it not being. Make the indicator part of the capture path, so capture without indication is not a state the application can reach. Done when: Capture cannot run without a visible indicator, verified by attempting to disable it in configuration and in code. Screen and audio are permitted separately. An excluded application produces no capture rows, verified by inspecting the store. Stopping capture takes effect immediately and the indicator clears. Do not build yet: No processing, queries or retention. ### Phase 2 · Disclosure when other people are involved Build: Prompt to disclose whenever audio capture begins, with suggested wording, and record whether disclosure happened. Mark sessions captured without disclosure. Provide no way to suppress the prompt permanently. Trap: A prompt with a do-not-ask-again option becomes a tool that silently records other people's conversations within a week, and the recording of that decision is a checkbox nobody remembers ticking. Prompt every time, keep the record, and make an undisclosed session visibly different from a disclosed one everywhere it appears. Done when: Audio capture prompts for disclosure every time it starts, with no permanent suppression available. Disclosure time is recorded when confirmed. An undisclosed session is marked in the session list and on any output derived from it. Screen capture alone does not prompt, since it involves nobody else. Do not build yet: No assistant queries yet. ### Phase 3 · Refusing the uses this should not have Build: Detect signals that the machine is in an assessment or interview context, such as known proctoring or assessment applications being in the foreground, and refuse to answer queries. Record the refusal. Provide no override. Trap: Detection here will be imperfect in both directions, and the temptation is to add an override for the false positives, which immediately makes the whole check optional. Accept the false positives, keep the check narrow enough that they are rare, and treat someone needing an override as a signal about the use rather than a gap to fill. Done when: A known assessment application in the foreground causes queries to be refused with a clear explanation. The refusal is recorded. No override exists, verified by looking for one. The detection list is a configuration file that can be extended but not emptied at runtime. Do not build yet: No local processing or retention yet. ### Phase 4 · Answers from context, kept local Build: Answer queries using recent captures, recording which captures each answer used. Run locally by default with any hosted model an explicit per-session choice. Show the context used alongside every answer. Trap: Sending the whole capture buffer to a hosted model on every query ships screen contents and call transcripts to a third party continuously, including from the sessions where you excluded an application but had it in the buffer from before. Select context deliberately, show what was sent, and make hosted use a per-session decision rather than a preference. Done when: Every answer shows which captures it used. Local processing is the default and a hosted model requires a per-session choice, verified by checking that no request leaves without one. Excluded content never enters the context, tested by excluding an application mid-session. The context sent to a hosted model is displayed before sending. Do not build yet: No retention or export yet. ### Phase 5 · Forgetting quickly Build: Short retention for screen text and transcripts, with disclosure records kept longer. Deletion removing captures, queries and their context references. Verify no capture text reaches logs or crash reports. Trap: Screen text and call transcripts in a log or a crash report leak exactly the material the whole design was protecting, and they get added by someone making debugging easier. Assert it in the test suite: scan every log and report path for capture fields and fail the build if any appear. Done when: Screen text and transcripts expire on a short retention while disclosure records survive. A test fails when a capture field is added to a log path, verified by deliberately adding one. Deletion removes captures, queries and context references together. Retention runs whether or not the application is open. Do not build yet: Nothing after this. ### Out of scope (and why) - Any invisibility: hiding from screen sharing, from capture, or from the people in the room. Its absence is the reason this build is defensible. - Use in interviews, exams and assessments, which the build actively refuses rather than merely discourages. - Cloud storage of captures, which would turn a local tool into a database of everything on your screen. - Real-time coaching during a live call, which is the positioning that makes the category what it is. ### README must contain - That there is no invisibility of any kind and why that is the design rather than an omission - That the capture indicator is part of the capture path and cannot be disabled - That audio capture prompts for disclosure every time with no permanent suppression - That assessment contexts block queries and there is no override - That captures expire quickly and a test asserts they never reach a log ===== AGENTS.md ===== # Agent instructions · Cluely indie build - Read `README.md` and `BUILD_PLAN.md` before writing code. The stack is fixed: Screen region capture and system audio, each separately permitted, Local models by default, with any hosted call an explicit per-session choice, An always-visible indicator that cannot be disabled, Short by default, with transcripts and screen text expiring separately, A native overlay application with a hotkey. Do not substitute. - Work one phase at a time, in order. Do not start a phase until every "Done when" item of the previous one passes. - Prefer the fewest moving parts that satisfy the step. No frameworks, services or dependencies the plan does not name. - Secrets live in `.env`, never in source or logs. Keep `.env.example` current when a variable is introduced. - Do not invent cryptography, security guarantees, APIs or compliance claims. - Add a focused test for every destructive, security-sensitive or data-loss path the plan names. - Run the project checks before declaring a phase complete, and record any deliberate shortcut in the README under "Tradeoffs". ## Known traps - Building an indicator that any setting can hide means the invisibility is one configuration change away, and the position that this tool is ethical rests entirely on it not being. Make the indicator part of the capture path, so capture without indication is not a state the application can reach. - A prompt with a do-not-ask-again option becomes a tool that silently records other people's conversations within a week, and the recording of that decision is a checkbox nobody remembers ticking. Prompt every time, keep the record, and make an undisclosed session visibly different from a disclosed one everywhere it appears. - Detection here will be imperfect in both directions, and the temptation is to add an override for the false positives, which immediately makes the whole check optional. Accept the false positives, keep the check narrow enough that they are rare, and treat someone needing an override as a signal about the use rather than a gap to fill. - Sending the whole capture buffer to a hosted model on every query ships screen contents and call transcripts to a third party continuously, including from the sessions where you excluded an application but had it in the buffer from before. Select context deliberately, show what was sent, and make hosted use a per-session decision rather than a preference. ===== BUILD_PLAN.md ===== # Build plan · Cluely A desktop assistant with access to what is on your screen and, with consent, what is said on your calls, where the engineering is in capturing selectively and locally, and the design is entirely about the capture being visible to everyone it affects. Phases are in dependency order. Each ends in a "Done when" list; treat an unticked item as a blocker, not a note. ## Phase 1 · Capture that announces itself Nobody near this machine could be unaware that capture is running. ### Steps 1. Tie the indicator to the capture path Capture without indication should not be a reachable state. Files: `src/Indicator.swift` 2. Permit screen and audio separately Different intrusions. Bundling them makes both harder to refuse. Files: `src/Permissions.swift` 3. Apply exclusions before writing A password manager or a private message window should never reach disk. Files: `src/Exclusions.swift` ### Done when - [ ] Capture cannot run without a visible indicator - [ ] Screen and audio permissions are separate - [ ] Excluded applications produce no rows - [ ] Stopping capture is immediate and visible ### Watch out - Building an indicator that any setting can hide means the invisibility is one configuration change away, and the position that this tool is ethical rests entirely on it not being. Make the indicator part of the capture path, so capture without indication is not a state the application can reach. ## Phase 2 · Disclosure when other people are involved Starting audio capture prompts you to tell the people on the call. ### Steps 1. Prompt on every audio capture start Every time. A remembered answer is not consent from the people on the call. Files: `src/Disclosure.swift` 2. Offer wording to use One sentence. Making it easy is what makes it happen. Files: `config/disclosure.md` 3. Mark undisclosed sessions everywhere In the list and on anything derived from them. Files: `src/Sessions.swift` ### Done when - [ ] Audio capture prompts every time - [ ] No permanent suppression exists - [ ] Undisclosed sessions are marked everywhere - [ ] Screen-only capture does not prompt ### Watch out - A prompt with a do-not-ask-again option becomes a tool that silently records other people's conversations within a week, and the recording of that decision is a checkbox nobody remembers ticking. Prompt every time, keep the record, and make an undisclosed session visibly different from a disclosed one everywhere it appears. ## Phase 3 · Refusing the uses this should not have The tool declines to operate as undisclosed assistance in an assessment. ### Steps 1. Detect narrow, well-known signals Narrow enough that false positives are rare, since there is no override. Files: `src/Assessment.swift` 2. Refuse and explain Not silently degrade. The user should know why. Files: `src/Query.swift` 3. Provide no override Its absence is the point. An override makes the check decorative. Files: `src/Assessment.swift` ### Done when - [ ] A known assessment application blocks queries - [ ] The refusal is explained and recorded - [ ] No override exists - [ ] The detection list cannot be emptied at runtime ### Watch out - Detection here will be imperfect in both directions, and the temptation is to add an override for the false positives, which immediately makes the whole check optional. Accept the false positives, keep the check narrow enough that they are rare, and treat someone needing an override as a signal about the use rather than a gap to fill. ## Phase 4 · Answers from context, kept local The assistant uses what it captured and you know exactly what it saw. ### Steps 1. Record the context per query Which captures. So you can answer what it saw. Files: `src/Query.swift` 2. Make hosted use per session Not a preference. A preference is set once and forgotten. Files: `src/ModelPolicy.swift` 3. Show what is sent before sending Screen contents leaving the machine deserves a look first. Files: `src/Review.swift` ### Done when - [ ] Every answer shows the captures it used - [ ] Local is default and hosted is per session - [ ] Excluded content never enters context - [ ] Context is shown before leaving the machine ### Watch out - Sending the whole capture buffer to a hosted model on every query ships screen contents and call transcripts to a third party continuously, including from the sessions where you excluded an application but had it in the buffer from before. Select context deliberately, show what was sent, and make hosted use a per-session decision rather than a preference. ## Not in this build - Invisibility of any kind. - Use in interviews, exams and assessments. - Cloud storage of captures. - Real-time coaching during a live call. ## After v1, if you want it - Answering from your own documents rather than only from what is on screen - A session summary you can keep after the captures expire - Per-application context rules, so a code editor and a browser are treated differently ===== .env.example ===== # Copy to .env and fill in. Never commit .env; this file documents it. # Required. Screen text and transcripts. The most sensitive file this build produces. DB_PATH=~/.local/share/assistant/captures.db # Required · secret. Encrypts the capture store at rest. DB_KEY=a keychain reference # Required. Present as a constant so the answer is visible. Capture without indication is not a reachable state. INDICATOR_DISABLE=impossible # Required. How long captures live. Minutes, because that is how long they are useful. CAPTURE_RETENTION_MINUTES=60 # Required. Much longer than the capture, because it is the evidence. DISCLOSURE_RETENTION_DAYS=1825 # Required. Loaded by the capture path before the first write, not applied at display. EXCLUSIONS_PATH=./config/exclusions.txt
You are building a lean indie version of Cluely. Create the following project files first, then implement the application by following them. Keep the files updated as decisions change. Do not collapse this into a single README or prompt. ===== README.md ===== # Cluely · indie build A desktop assistant with access to what is on your screen and, with consent, what is said on your calls, where the engineering is in capturing selectively and locally, and the design is entirely about the capture being visible to everyone it affects. Estimated effort: **multi-day**. Work `BUILD_PLAN.md` top to bottom · every phase ends in a check that has to pass before the next one starts. ## Stack | Part | Choice | Why | | --- | --- | --- | | Capture | Screen region capture and system audio, each separately permitted | they are different intrusions and deserve different consent | | Processing | Local models by default, with any hosted call an explicit per-session choice | screen contents and call audio are the most sensitive things on a machine | | Indication | An always-visible indicator that cannot be disabled | the whole ethical position rests on the capture being apparent | | Retention | Short by default, with transcripts and screen text expiring separately | captured context loses value in minutes and stays sensitive for years | | Runtime | A native overlay application with a hotkey | it has to be reachable without leaving what you are doing | ## Before you start Have every one of these ready. The plan assumes them from step one. - [ ] **A machine whose capture permissions you understand** · free - Why: Screen and audio capture each need a system permission, and what each grants and how it is requested differs by platform and version. - Get it: Read your platform's current documentation for both permissions before designing the consent flow. - Verify: Both permissions can be requested separately and their state read - [ ] **A local model runner** · free, needs memory - Why: Screen contents and call transcripts are the most sensitive material on a machine and the default must not be sending them anywhere. - Get it: Any local runner with a model capable of answering from provided context. - Verify: A query answers from local context with networking disabled - [ ] **Your recording consent position** · free to read; an hour of advice if this is for work - Why: Capturing call audio records other people, and the rules attach to the recording rather than to the software being visible. - Get it: Identify where the people you call are, take the strictest applicable rule, and write down what you concluded. - Verify: A written note names the jurisdictions and the rule applied - [ ] **Your exclusion list, written before capture** · free - Why: A password manager, a private message window or a medical portal captured once is captured, and deciding the list afterwards is deciding it too late. - Get it: List applications and window title patterns that must never be captured. Err wide. - Verify: The list is loaded by the capture path before the first run - [ ] **A list of assessment and proctoring applications** · free - Why: Phase 3 refuses to operate in those contexts, and the check is only as good as the list. - Get it: Identify the proctoring and assessment tools in use where you are. Keep the list narrow so false positives stay rare, since there is no override. - Verify: A list exists and blocking is confirmed with at least one of them running ## Quick start Follow Phase 1 in `BUILD_PLAN.md`; it creates the project. Then copy `.env.example` to `.env` and fill in the values it documents. ## Honest limits This build deliberately does not replace: - Invisibility of any kind. - Use in interviews, exams and assessments. - Cloud storage of captures. - Real-time coaching during a live call. - Screen-share invisibility that has actually been tested against Zoom, Meet, Teams and OS screenshot tools - Sub-second latency and the prompt tuning that makes answers short enough to read while someone is talking - System audio capture that just works without you installing and routing a virtual audio device - Mobile and browser-extension coverage, plus a hosted account so your setup follows you to another machine - Somebody else's legal and PR exposure for a product whose pitch is 'cheat on everything' If one of those is essential to you, that is the reason to keep paying for Cluely, and the README should say so rather than pretend. ===== BRIEF.md ===== # Build brief · Cluely The one-shot brief this plan expands. `BUILD_PLAN.md` (or `MILESTONES.md`) is the same sequence broken into steps and checks; where the two disagree, the plan wins. Build me a desktop assistant that reads your screen and hears your calls, built to be disclosed to replace Cluely. Build it in phases, in the order below. Do not write the whole thing in one pass. Finish a phase, run its "Done when" check, fix what fails, and only then start the next phase. ### Rule zero This category is marketed around being invisible: an overlay that watches your screen and listens to your calls and feeds you answers, positioned for interviews, exams and sales calls where the other party does not know. Build the tool; do not build the invisibility. Two reasons, and neither is squeamishness. Undisclosed assistance in an interview or an assessment is misrepresentation, and it is the user who carries that, not the tool. And listening to a call means recording other people, which is governed by consent rules that attach to the recording regardless of whether anyone can see the software. So this build: has no screen-sharing evasion, no hidden-from-capture mode, no invisibility of any kind. It prompts to disclose when audio capture starts and records whether you did. It refuses to run in modes it can detect are assessments. Audio and screen capture are separately consented and separately indicated, with an indicator that cannot be turned off. The genuinely useful version of this is an assistant for your own work: your documents, your notes, your calls with consent. That version is worth building, and it is what follows. ### Stack (fixed, do not substitute) - Capture: Screen region capture and system audio, each separately permitted · they are different intrusions and deserve different consent - Processing: Local models by default, with any hosted call an explicit per-session choice · screen contents and call audio are the most sensitive things on a machine - Indication: An always-visible indicator that cannot be disabled · the whole ethical position rests on the capture being apparent - Retention: Short by default, with transcripts and screen text expiring separately · captured context loses value in minutes and stays sensitive for years - Runtime: A native overlay application with a hotkey · it has to be reachable without leaving what you are doing ### Data model (create this before Phase 1) - sessions(id, started_at, ended_at, screen_capture, audio_capture, disclosed_at, model_policy) - captures(id, session_id, kind, at, text, region_json, redacted) · kind is screen_text or transcript - exclusions(id, kind, pattern) · applications and window titles never captured, applied before writing - queries(id, session_id, prompt, response, model, at, capture_ids_json) · what context each answer used - consents(session_id, scope, granted_at, evidence) · screen and audio consented separately - assessment_blocks(id, detected_signal, at) · when the tool refused to run and why - A query records which captures it used, so you can always answer what the assistant saw when it said something. ### Phase 1 · Capture that announces itself Build: Screen and audio capture as separately requested permissions, each with its own visible indicator that cannot be hidden or disabled. Apply an exclusion list before writing anything. Make stopping capture immediate and obvious. Trap: Building an indicator that any setting can hide means the invisibility is one configuration change away, and the position that this tool is ethical rests entirely on it not being. Make the indicator part of the capture path, so capture without indication is not a state the application can reach. Done when: Capture cannot run without a visible indicator, verified by attempting to disable it in configuration and in code. Screen and audio are permitted separately. An excluded application produces no capture rows, verified by inspecting the store. Stopping capture takes effect immediately and the indicator clears. Do not build yet: No processing, queries or retention. ### Phase 2 · Disclosure when other people are involved Build: Prompt to disclose whenever audio capture begins, with suggested wording, and record whether disclosure happened. Mark sessions captured without disclosure. Provide no way to suppress the prompt permanently. Trap: A prompt with a do-not-ask-again option becomes a tool that silently records other people's conversations within a week, and the recording of that decision is a checkbox nobody remembers ticking. Prompt every time, keep the record, and make an undisclosed session visibly different from a disclosed one everywhere it appears. Done when: Audio capture prompts for disclosure every time it starts, with no permanent suppression available. Disclosure time is recorded when confirmed. An undisclosed session is marked in the session list and on any output derived from it. Screen capture alone does not prompt, since it involves nobody else. Do not build yet: No assistant queries yet. ### Phase 3 · Refusing the uses this should not have Build: Detect signals that the machine is in an assessment or interview context, such as known proctoring or assessment applications being in the foreground, and refuse to answer queries. Record the refusal. Provide no override. Trap: Detection here will be imperfect in both directions, and the temptation is to add an override for the false positives, which immediately makes the whole check optional. Accept the false positives, keep the check narrow enough that they are rare, and treat someone needing an override as a signal about the use rather than a gap to fill. Done when: A known assessment application in the foreground causes queries to be refused with a clear explanation. The refusal is recorded. No override exists, verified by looking for one. The detection list is a configuration file that can be extended but not emptied at runtime. Do not build yet: No local processing or retention yet. ### Phase 4 · Answers from context, kept local Build: Answer queries using recent captures, recording which captures each answer used. Run locally by default with any hosted model an explicit per-session choice. Show the context used alongside every answer. Trap: Sending the whole capture buffer to a hosted model on every query ships screen contents and call transcripts to a third party continuously, including from the sessions where you excluded an application but had it in the buffer from before. Select context deliberately, show what was sent, and make hosted use a per-session decision rather than a preference. Done when: Every answer shows which captures it used. Local processing is the default and a hosted model requires a per-session choice, verified by checking that no request leaves without one. Excluded content never enters the context, tested by excluding an application mid-session. The context sent to a hosted model is displayed before sending. Do not build yet: No retention or export yet. ### Phase 5 · Forgetting quickly Build: Short retention for screen text and transcripts, with disclosure records kept longer. Deletion removing captures, queries and their context references. Verify no capture text reaches logs or crash reports. Trap: Screen text and call transcripts in a log or a crash report leak exactly the material the whole design was protecting, and they get added by someone making debugging easier. Assert it in the test suite: scan every log and report path for capture fields and fail the build if any appear. Done when: Screen text and transcripts expire on a short retention while disclosure records survive. A test fails when a capture field is added to a log path, verified by deliberately adding one. Deletion removes captures, queries and context references together. Retention runs whether or not the application is open. Do not build yet: Nothing after this. ### Out of scope (and why) - Any invisibility: hiding from screen sharing, from capture, or from the people in the room. Its absence is the reason this build is defensible. - Use in interviews, exams and assessments, which the build actively refuses rather than merely discourages. - Cloud storage of captures, which would turn a local tool into a database of everything on your screen. - Real-time coaching during a live call, which is the positioning that makes the category what it is. ### README must contain - That there is no invisibility of any kind and why that is the design rather than an omission - That the capture indicator is part of the capture path and cannot be disabled - That audio capture prompts for disclosure every time with no permanent suppression - That assessment contexts block queries and there is no override - That captures expire quickly and a test asserts they never reach a log ===== AGENTS.md ===== # Agent instructions · Cluely indie build - Read `README.md` and `BUILD_PLAN.md` before writing code. The stack is fixed: Screen region capture and system audio, each separately permitted, Local models by default, with any hosted call an explicit per-session choice, An always-visible indicator that cannot be disabled, Short by default, with transcripts and screen text expiring separately, A native overlay application with a hotkey. Do not substitute. - Work one phase at a time, in order. Do not start a phase until every "Done when" item of the previous one passes. - Prefer the fewest moving parts that satisfy the step. No frameworks, services or dependencies the plan does not name. - Secrets live in `.env`, never in source or logs. Keep `.env.example` current when a variable is introduced. - Do not invent cryptography, security guarantees, APIs or compliance claims. - Add a focused test for every destructive, security-sensitive or data-loss path the plan names. - Run the project checks before declaring a phase complete, and record any deliberate shortcut in the README under "Tradeoffs". ## Known traps - Building an indicator that any setting can hide means the invisibility is one configuration change away, and the position that this tool is ethical rests entirely on it not being. Make the indicator part of the capture path, so capture without indication is not a state the application can reach. - A prompt with a do-not-ask-again option becomes a tool that silently records other people's conversations within a week, and the recording of that decision is a checkbox nobody remembers ticking. Prompt every time, keep the record, and make an undisclosed session visibly different from a disclosed one everywhere it appears. - Detection here will be imperfect in both directions, and the temptation is to add an override for the false positives, which immediately makes the whole check optional. Accept the false positives, keep the check narrow enough that they are rare, and treat someone needing an override as a signal about the use rather than a gap to fill. - Sending the whole capture buffer to a hosted model on every query ships screen contents and call transcripts to a third party continuously, including from the sessions where you excluded an application but had it in the buffer from before. Select context deliberately, show what was sent, and make hosted use a per-session decision rather than a preference. ===== BUILD_PLAN.md ===== # Build plan · Cluely A desktop assistant with access to what is on your screen and, with consent, what is said on your calls, where the engineering is in capturing selectively and locally, and the design is entirely about the capture being visible to everyone it affects. Phases are in dependency order. Each ends in a "Done when" list; treat an unticked item as a blocker, not a note. ## Phase 1 · Capture that announces itself Nobody near this machine could be unaware that capture is running. ### Steps 1. Tie the indicator to the capture path Capture without indication should not be a reachable state. Files: `src/Indicator.swift` 2. Permit screen and audio separately Different intrusions. Bundling them makes both harder to refuse. Files: `src/Permissions.swift` 3. Apply exclusions before writing A password manager or a private message window should never reach disk. Files: `src/Exclusions.swift` ### Done when - [ ] Capture cannot run without a visible indicator - [ ] Screen and audio permissions are separate - [ ] Excluded applications produce no rows - [ ] Stopping capture is immediate and visible ### Watch out - Building an indicator that any setting can hide means the invisibility is one configuration change away, and the position that this tool is ethical rests entirely on it not being. Make the indicator part of the capture path, so capture without indication is not a state the application can reach. ## Phase 2 · Disclosure when other people are involved Starting audio capture prompts you to tell the people on the call. ### Steps 1. Prompt on every audio capture start Every time. A remembered answer is not consent from the people on the call. Files: `src/Disclosure.swift` 2. Offer wording to use One sentence. Making it easy is what makes it happen. Files: `config/disclosure.md` 3. Mark undisclosed sessions everywhere In the list and on anything derived from them. Files: `src/Sessions.swift` ### Done when - [ ] Audio capture prompts every time - [ ] No permanent suppression exists - [ ] Undisclosed sessions are marked everywhere - [ ] Screen-only capture does not prompt ### Watch out - A prompt with a do-not-ask-again option becomes a tool that silently records other people's conversations within a week, and the recording of that decision is a checkbox nobody remembers ticking. Prompt every time, keep the record, and make an undisclosed session visibly different from a disclosed one everywhere it appears. ## Phase 3 · Refusing the uses this should not have The tool declines to operate as undisclosed assistance in an assessment. ### Steps 1. Detect narrow, well-known signals Narrow enough that false positives are rare, since there is no override. Files: `src/Assessment.swift` 2. Refuse and explain Not silently degrade. The user should know why. Files: `src/Query.swift` 3. Provide no override Its absence is the point. An override makes the check decorative. Files: `src/Assessment.swift` ### Done when - [ ] A known assessment application blocks queries - [ ] The refusal is explained and recorded - [ ] No override exists - [ ] The detection list cannot be emptied at runtime ### Watch out - Detection here will be imperfect in both directions, and the temptation is to add an override for the false positives, which immediately makes the whole check optional. Accept the false positives, keep the check narrow enough that they are rare, and treat someone needing an override as a signal about the use rather than a gap to fill. ## Phase 4 · Answers from context, kept local The assistant uses what it captured and you know exactly what it saw. ### Steps 1. Record the context per query Which captures. So you can answer what it saw. Files: `src/Query.swift` 2. Make hosted use per session Not a preference. A preference is set once and forgotten. Files: `src/ModelPolicy.swift` 3. Show what is sent before sending Screen contents leaving the machine deserves a look first. Files: `src/Review.swift` ### Done when - [ ] Every answer shows the captures it used - [ ] Local is default and hosted is per session - [ ] Excluded content never enters context - [ ] Context is shown before leaving the machine ### Watch out - Sending the whole capture buffer to a hosted model on every query ships screen contents and call transcripts to a third party continuously, including from the sessions where you excluded an application but had it in the buffer from before. Select context deliberately, show what was sent, and make hosted use a per-session decision rather than a preference. ## Not in this build - Invisibility of any kind. - Use in interviews, exams and assessments. - Cloud storage of captures. - Real-time coaching during a live call. ## After v1, if you want it - Answering from your own documents rather than only from what is on screen - A session summary you can keep after the captures expire - Per-application context rules, so a code editor and a browser are treated differently ===== .env.example ===== # Copy to .env and fill in. Never commit .env; this file documents it. # Required. Screen text and transcripts. The most sensitive file this build produces. DB_PATH=~/.local/share/assistant/captures.db # Required · secret. Encrypts the capture store at rest. DB_KEY=a keychain reference # Required. Present as a constant so the answer is visible. Capture without indication is not a reachable state. INDICATOR_DISABLE=impossible # Required. How long captures live. Minutes, because that is how long they are useful. CAPTURE_RETENTION_MINUTES=60 # Required. Much longer than the capture, because it is the evidence. DISCLOSURE_RETENTION_DAYS=1825 # Required. Loaded by the capture path before the first write, not applied at display. EXCLUSIONS_PATH=./config/exclusions.txt
You are building a production product version of Cluely. Create the following project files first, then implement the application by following them. Keep the files updated as decisions change. Do not collapse this into a single README or prompt. ===== PRODUCT.md ===== # Cluely · product brief ## Problem The core loop is genuinely thin: capture a screenshot, transcribe the mic, feed both to a multimodal model, stream the answer into a transparent always-on-top window on a hotkey. An agent gets that working in a session, and it will feel uncomfortably close to the demo. The gaps are the unglamorous parts: capturing the other side's audio takes virtual audio devices, latency has to beat the conversation, and the headline trick of staying invisible in screen shares depends on fragile platform window flags that vary by OS and conferencing app. Your DIY version will work fine when you are alone with your own screen, and may quietly betray you the one time it matters. ## Product outcome An assistant that can see your screen and hear your calls, where everyone affected can tell that it is running, and which refuses the uses that made the category notorious. ## Target user A builder who needs a maintainable product foundation, not a one-off demo. ## Required capabilities - An OpenAI API key (or any multimodal chat endpoint) in .env - macOS or Windows desktop, plus screen recording and microphone permissions - A virtual audio device for other-party audio: BlackHole on macOS, VB-Cable or WASAPI loopback on Windows - Node 20 and willingness to sign or self-trust an unsigned Electron build ## Explicit non-goals for v1 - Invisibility of any kind. - Use in interviews, exams and assessments. - Cloud storage of captures. - Real-time coaching during a live call. - Screen-share invisibility that has actually been tested against Zoom, Meet, Teams and OS screenshot tools - Sub-second latency and the prompt tuning that makes answers short enough to read while someone is talking - System audio capture that just works without you installing and routing a virtual audio device - Mobile and browser-extension coverage, plus a hosted account so your setup follows you to another machine - Somebody else's legal and PR exposure for a product whose pitch is 'cheat on everything' ## Success criteria - Capture without a visible indicator is confirmed unreachable - Audio capture is confirmed to prompt every time - An assessment context is confirmed to block queries with no override - Excluded content is confirmed never to enter context - The suite is confirmed to fail when a capture field reaches a log ===== BRIEF.md ===== # Build brief · Cluely The one-shot brief this plan expands. `BUILD_PLAN.md` (or `MILESTONES.md`) is the same sequence broken into steps and checks; where the two disagree, the plan wins. Build me a desktop assistant that reads your screen and hears your calls, built to be disclosed to replace Cluely. Build it in phases, in the order below. Do not write the whole thing in one pass. Finish a phase, run its "Done when" check, fix what fails, and only then start the next phase. ### Rule zero This category is marketed around being invisible: an overlay that watches your screen and listens to your calls and feeds you answers, positioned for interviews, exams and sales calls where the other party does not know. Build the tool; do not build the invisibility. Two reasons, and neither is squeamishness. Undisclosed assistance in an interview or an assessment is misrepresentation, and it is the user who carries that, not the tool. And listening to a call means recording other people, which is governed by consent rules that attach to the recording regardless of whether anyone can see the software. So this build: has no screen-sharing evasion, no hidden-from-capture mode, no invisibility of any kind. It prompts to disclose when audio capture starts and records whether you did. It refuses to run in modes it can detect are assessments. Audio and screen capture are separately consented and separately indicated, with an indicator that cannot be turned off. The genuinely useful version of this is an assistant for your own work: your documents, your notes, your calls with consent. That version is worth building, and it is what follows. ### Stack (fixed, do not substitute) - Capture: Screen region capture and system audio, each separately permitted · they are different intrusions and deserve different consent - Processing: Local models by default, with any hosted call an explicit per-session choice · screen contents and call audio are the most sensitive things on a machine - Indication: An always-visible indicator that cannot be disabled · the whole ethical position rests on the capture being apparent - Retention: Short by default, with transcripts and screen text expiring separately · captured context loses value in minutes and stays sensitive for years - Runtime: A native overlay application with a hotkey · it has to be reachable without leaving what you are doing ### Data model (create this before Phase 1) - sessions(id, started_at, ended_at, screen_capture, audio_capture, disclosed_at, model_policy) - captures(id, session_id, kind, at, text, region_json, redacted) · kind is screen_text or transcript - exclusions(id, kind, pattern) · applications and window titles never captured, applied before writing - queries(id, session_id, prompt, response, model, at, capture_ids_json) · what context each answer used - consents(session_id, scope, granted_at, evidence) · screen and audio consented separately - assessment_blocks(id, detected_signal, at) · when the tool refused to run and why - A query records which captures it used, so you can always answer what the assistant saw when it said something. ### Phase 1 · Capture that announces itself Build: Screen and audio capture as separately requested permissions, each with its own visible indicator that cannot be hidden or disabled. Apply an exclusion list before writing anything. Make stopping capture immediate and obvious. Trap: Building an indicator that any setting can hide means the invisibility is one configuration change away, and the position that this tool is ethical rests entirely on it not being. Make the indicator part of the capture path, so capture without indication is not a state the application can reach. Done when: Capture cannot run without a visible indicator, verified by attempting to disable it in configuration and in code. Screen and audio are permitted separately. An excluded application produces no capture rows, verified by inspecting the store. Stopping capture takes effect immediately and the indicator clears. Do not build yet: No processing, queries or retention. ### Phase 2 · Disclosure when other people are involved Build: Prompt to disclose whenever audio capture begins, with suggested wording, and record whether disclosure happened. Mark sessions captured without disclosure. Provide no way to suppress the prompt permanently. Trap: A prompt with a do-not-ask-again option becomes a tool that silently records other people's conversations within a week, and the recording of that decision is a checkbox nobody remembers ticking. Prompt every time, keep the record, and make an undisclosed session visibly different from a disclosed one everywhere it appears. Done when: Audio capture prompts for disclosure every time it starts, with no permanent suppression available. Disclosure time is recorded when confirmed. An undisclosed session is marked in the session list and on any output derived from it. Screen capture alone does not prompt, since it involves nobody else. Do not build yet: No assistant queries yet. ### Phase 3 · Refusing the uses this should not have Build: Detect signals that the machine is in an assessment or interview context, such as known proctoring or assessment applications being in the foreground, and refuse to answer queries. Record the refusal. Provide no override. Trap: Detection here will be imperfect in both directions, and the temptation is to add an override for the false positives, which immediately makes the whole check optional. Accept the false positives, keep the check narrow enough that they are rare, and treat someone needing an override as a signal about the use rather than a gap to fill. Done when: A known assessment application in the foreground causes queries to be refused with a clear explanation. The refusal is recorded. No override exists, verified by looking for one. The detection list is a configuration file that can be extended but not emptied at runtime. Do not build yet: No local processing or retention yet. ### Phase 4 · Answers from context, kept local Build: Answer queries using recent captures, recording which captures each answer used. Run locally by default with any hosted model an explicit per-session choice. Show the context used alongside every answer. Trap: Sending the whole capture buffer to a hosted model on every query ships screen contents and call transcripts to a third party continuously, including from the sessions where you excluded an application but had it in the buffer from before. Select context deliberately, show what was sent, and make hosted use a per-session decision rather than a preference. Done when: Every answer shows which captures it used. Local processing is the default and a hosted model requires a per-session choice, verified by checking that no request leaves without one. Excluded content never enters the context, tested by excluding an application mid-session. The context sent to a hosted model is displayed before sending. Do not build yet: No retention or export yet. ### Phase 5 · Forgetting quickly Build: Short retention for screen text and transcripts, with disclosure records kept longer. Deletion removing captures, queries and their context references. Verify no capture text reaches logs or crash reports. Trap: Screen text and call transcripts in a log or a crash report leak exactly the material the whole design was protecting, and they get added by someone making debugging easier. Assert it in the test suite: scan every log and report path for capture fields and fail the build if any appear. Done when: Screen text and transcripts expire on a short retention while disclosure records survive. A test fails when a capture field is added to a log path, verified by deliberately adding one. Deletion removes captures, queries and context references together. Retention runs whether or not the application is open. Do not build yet: Nothing after this. ### Out of scope (and why) - Any invisibility: hiding from screen sharing, from capture, or from the people in the room. Its absence is the reason this build is defensible. - Use in interviews, exams and assessments, which the build actively refuses rather than merely discourages. - Cloud storage of captures, which would turn a local tool into a database of everything on your screen. - Real-time coaching during a live call, which is the positioning that makes the category what it is. ### README must contain - That there is no invisibility of any kind and why that is the design rather than an omission - That the capture indicator is part of the capture path and cannot be disabled - That audio capture prompts for disclosure every time with no permanent suppression - That assessment contexts block queries and there is no override - That captures expire quickly and a test asserts they never reach a log ===== ARCHITECTURE.md ===== # Architecture · Cluely ## Stack | Part | Choice | Why | | --- | --- | --- | | Capture | Screen region capture and system audio, each separately permitted | they are different intrusions and deserve different consent | | Processing | Local models by default, with any hosted call an explicit per-session choice | screen contents and call audio are the most sensitive things on a machine | | Indication | An always-visible indicator that cannot be disabled | the whole ethical position rests on the capture being apparent | | Retention | Short by default, with transcripts and screen text expiring separately | captured context loses value in minutes and stays sensitive for years | | Runtime | A native overlay application with a hotkey | it has to be reachable without leaving what you are doing | ## Modules Each module has one owner concern and a documented way to replace it. | Module | Owns | How to replace it | | --- | --- | --- | | Capture | Screen and audio, separately permitted and indicated. | Any implementation, provided the indicator is inseparable from capture. | | Disclosure | Prompting and recording for audio sessions. | Not swappable for a remembered preference, which is not consent from the other party. | | Refusal | Blocking in assessment contexts. | Any detection, provided no override exists. | | Context | Selecting and recording what each answer used. | Any selection, provided it is shown before anything leaves the machine. | | Retention | Short expiry and log exclusion. | Any policy, provided the log assertion stays in the suite. | ## Configuration Every runtime setting is an environment variable documented in `.env.example`, validated at startup, with a safe local default wherever one exists. - `DB_PATH` · required · Screen text and transcripts. The most sensitive file this build produces. - `DB_KEY` · required, secret · Encrypts the capture store at rest. - `INDICATOR_DISABLE` · required · Present as a constant so the answer is visible. Capture without indication is not a reachable state. - `CAPTURE_RETENTION_MINUTES` · required · How long captures live. Minutes, because that is how long they are useful. - `DISCLOSURE_RETENTION_DAYS` · required · Much longer than the capture, because it is the evidence. - `EXCLUSIONS_PATH` · required · Loaded by the capture path before the first write, not applied at display. ## Production baseline - Security: least privilege, input validation at every boundary, secret redaction in logs, rate limits on abuse-prone paths, no invented security primitives. - Data: explicit schema and migrations, transactional writes where integrity matters, backup and restore procedures that have been exercised. - Integrations: adapters around third-party providers, idempotent webhook or job processing, bounded retries, timeouts. - Observability: structured logs with request or operation ids, an error-tracking hook, and health and readiness checks where a server exists. - Quality: unit tests for domain rules, integration tests at module boundaries, one end-to-end test of the critical path. ## Decision records For each dependency in the stack table, keep a short note: why it was chosen, its failure mode, and how it is replaced. Do not add infrastructure until a requirement in `PRODUCT.md` justifies it. ===== AGENTS.md ===== # Agent instructions · Cluely product build - Read `PRODUCT.md` and `ARCHITECTURE.md` before changing code. The stack is fixed: Screen region capture and system audio, each separately permitted, Local models by default, with any hosted call an explicit per-session choice, An always-visible indicator that cannot be disabled, Short by default, with transcripts and screen text expiring separately, A native overlay application with a hotkey. - Implement milestone by milestone from `MILESTONES.md`; keep each change reviewable and leave the application runnable at every commit. - Treat authentication, payments, encryption, imports, webhooks and destructive actions as high-risk boundaries when present. - Never invent cryptography or silently weaken a requirement to make a check pass. - Put every external service behind an interface with a deterministic fake for tests. - Add migrations and rollback or recovery notes for every persistent data change. - Log useful operational context without credentials, tokens, passwords or personal data. - Update documentation and run every check before completing a milestone. ## Known traps - Building an indicator that any setting can hide means the invisibility is one configuration change away, and the position that this tool is ethical rests entirely on it not being. Make the indicator part of the capture path, so capture without indication is not a state the application can reach. - A prompt with a do-not-ask-again option becomes a tool that silently records other people's conversations within a week, and the recording of that decision is a checkbox nobody remembers ticking. Prompt every time, keep the record, and make an undisclosed session visibly different from a disclosed one everywhere it appears. - Detection here will be imperfect in both directions, and the temptation is to add an override for the false positives, which immediately makes the whole check optional. Accept the false positives, keep the check narrow enough that they are rare, and treat someone needing an override as a signal about the use rather than a gap to fill. - Sending the whole capture buffer to a hosted model on every query ships screen contents and call transcripts to a third party continuously, including from the sessions where you excluded an application but had it in the buffer from before. Select context deliberately, show what was sent, and make hosted use a per-session decision rather than a preference. - Screen text and call transcripts in a log or a crash report leak exactly the material the whole design was protecting, and they get added by someone making debugging easier. Assert it in the test suite: scan every log and report path for capture fields and fail the build if any appear. ===== MILESTONES.md ===== # Delivery milestones · Cluely Estimated effort: **multi-day** for the indie phases; the production-only milestones add the trust and operability layer. ## M1 · Capture that announces itself Nobody near this machine could be unaware that capture is running. ### Steps 1. Tie the indicator to the capture path Capture without indication should not be a reachable state. Files: `src/Indicator.swift` 2. Permit screen and audio separately Different intrusions. Bundling them makes both harder to refuse. Files: `src/Permissions.swift` 3. Apply exclusions before writing A password manager or a private message window should never reach disk. Files: `src/Exclusions.swift` ### Done when - [ ] Capture cannot run without a visible indicator - [ ] Screen and audio permissions are separate - [ ] Excluded applications produce no rows - [ ] Stopping capture is immediate and visible ### Watch out - Building an indicator that any setting can hide means the invisibility is one configuration change away, and the position that this tool is ethical rests entirely on it not being. Make the indicator part of the capture path, so capture without indication is not a state the application can reach. ## M2 · Disclosure when other people are involved Starting audio capture prompts you to tell the people on the call. ### Steps 1. Prompt on every audio capture start Every time. A remembered answer is not consent from the people on the call. Files: `src/Disclosure.swift` 2. Offer wording to use One sentence. Making it easy is what makes it happen. Files: `config/disclosure.md` 3. Mark undisclosed sessions everywhere In the list and on anything derived from them. Files: `src/Sessions.swift` ### Done when - [ ] Audio capture prompts every time - [ ] No permanent suppression exists - [ ] Undisclosed sessions are marked everywhere - [ ] Screen-only capture does not prompt ### Watch out - A prompt with a do-not-ask-again option becomes a tool that silently records other people's conversations within a week, and the recording of that decision is a checkbox nobody remembers ticking. Prompt every time, keep the record, and make an undisclosed session visibly different from a disclosed one everywhere it appears. ## M3 · Refusing the uses this should not have The tool declines to operate as undisclosed assistance in an assessment. ### Steps 1. Detect narrow, well-known signals Narrow enough that false positives are rare, since there is no override. Files: `src/Assessment.swift` 2. Refuse and explain Not silently degrade. The user should know why. Files: `src/Query.swift` 3. Provide no override Its absence is the point. An override makes the check decorative. Files: `src/Assessment.swift` ### Done when - [ ] A known assessment application blocks queries - [ ] The refusal is explained and recorded - [ ] No override exists - [ ] The detection list cannot be emptied at runtime ### Watch out - Detection here will be imperfect in both directions, and the temptation is to add an override for the false positives, which immediately makes the whole check optional. Accept the false positives, keep the check narrow enough that they are rare, and treat someone needing an override as a signal about the use rather than a gap to fill. ## M4 · Answers from context, kept local The assistant uses what it captured and you know exactly what it saw. ### Steps 1. Record the context per query Which captures. So you can answer what it saw. Files: `src/Query.swift` 2. Make hosted use per session Not a preference. A preference is set once and forgotten. Files: `src/ModelPolicy.swift` 3. Show what is sent before sending Screen contents leaving the machine deserves a look first. Files: `src/Review.swift` ### Done when - [ ] Every answer shows the captures it used - [ ] Local is default and hosted is per session - [ ] Excluded content never enters context - [ ] Context is shown before leaving the machine ### Watch out - Sending the whole capture buffer to a hosted model on every query ships screen contents and call transcripts to a third party continuously, including from the sessions where you excluded an application but had it in the buffer from before. Select context deliberately, show what was sent, and make hosted use a per-session decision rather than a preference. ## M5 · Forgetting quickly (production only) Captured context expires fast and deletion is complete. ### Steps 1. Expire captures quickly Their value is minutes. Their sensitivity is years. Files: `src/Retention.swift` 2. Keep disclosure records longer They are the evidence the capture was disclosed. Files: `src/Retention.swift` 3. Assert captures never reach logs In the suite, with a deliberately added field to prove the check works. Files: `tests/NoCaptureInLogsTests.swift` ### Done when - [ ] Captures expire while disclosure records survive - [ ] The suite fails when a capture field reaches a log - [ ] Deletion removes captures, queries and references - [ ] Retention runs without the application open ### Watch out - Screen text and call transcripts in a log or a crash report leak exactly the material the whole design was protecting, and they get added by someone making debugging easier. Assert it in the test suite: scan every log and report path for capture fields and fail the build if any appear. ===== OPERATIONS.md ===== # Operations · Cluely ## Backup Captures should mostly not be backed up at all, since they expire in an hour and are the most sensitive data here. Disclosure records are the thing worth retaining, and they are small. ## Restore Restore and confirm retention resumes immediately, since restoring expired captures recreates exactly the material the short retention exists to remove. Do a restore drill before the first real user, and write the date here when it passes. ## Monitoring Undisclosed session count is the number that matters. A rising count means the disclosure prompt is being dismissed, which is a use question rather than a technical one. ## Incident checklist Capture text appearing in a log or crash report is the incident, and the suite assertion is the control. If it was removed to make debugging easier, that is the change to revert rather than the finding to explain. 1. Contain the issue without destroying evidence or user data. 2. Record the timeline and affected scope. 3. Rotate exposed secrets and revoke compromised sessions or credentials. 4. Restore from a verified backup when needed. 5. Document the root cause, the remediation and the regression test. ## Release gate - [ ] Capture without a visible indicator is confirmed unreachable - [ ] Audio capture is confirmed to prompt every time - [ ] An assessment context is confirmed to block queries with no override - [ ] Excluded content is confirmed never to enter context - [ ] The suite is confirmed to fail when a capture field reaches a log ## Launch constraint Do not market omitted Cluely capabilities as implemented. The non-goals in `PRODUCT.md` remain user-visible limitations until they are deliberately delivered. ===== .env.example ===== # Copy to .env and fill in. Never commit .env; this file documents it. # Required. Screen text and transcripts. The most sensitive file this build produces. DB_PATH=~/.local/share/assistant/captures.db # Required · secret. Encrypts the capture store at rest. DB_KEY=a keychain reference # Required. Present as a constant so the answer is visible. Capture without indication is not a reachable state. INDICATOR_DISABLE=impossible # Required. How long captures live. Minutes, because that is how long they are useful. CAPTURE_RETENTION_MINUTES=60 # Required. Much longer than the capture, because it is the evidence. DISCLOSURE_RETENTION_DAYS=1825 # Required. Loaded by the capture path before the first write, not applied at display. EXCLUSIONS_PATH=./config/exclusions.txt
# Cluely · indie build A desktop assistant with access to what is on your screen and, with consent, what is said on your calls, where the engineering is in capturing selectively and locally, and the design is entirely about the capture being visible to everyone it affects. Estimated effort: **multi-day**. Work `BUILD_PLAN.md` top to bottom · every phase ends in a check that has to pass before the next one starts. ## Stack | Part | Choice | Why | | --- | --- | --- | | Capture | Screen region capture and system audio, each separately permitted | they are different intrusions and deserve different consent | | Processing | Local models by default, with any hosted call an explicit per-session choice | screen contents and call audio are the most sensitive things on a machine | | Indication | An always-visible indicator that cannot be disabled | the whole ethical position rests on the capture being apparent | | Retention | Short by default, with transcripts and screen text expiring separately | captured context loses value in minutes and stays sensitive for years | | Runtime | A native overlay application with a hotkey | it has to be reachable without leaving what you are doing | ## Before you start Have every one of these ready. The plan assumes them from step one. - [ ] **A machine whose capture permissions you understand** · free - Why: Screen and audio capture each need a system permission, and what each grants and how it is requested differs by platform and version. - Get it: Read your platform's current documentation for both permissions before designing the consent flow. - Verify: Both permissions can be requested separately and their state read - [ ] **A local model runner** · free, needs memory - Why: Screen contents and call transcripts are the most sensitive material on a machine and the default must not be sending them anywhere. - Get it: Any local runner with a model capable of answering from provided context. - Verify: A query answers from local context with networking disabled - [ ] **Your recording consent position** · free to read; an hour of advice if this is for work - Why: Capturing call audio records other people, and the rules attach to the recording rather than to the software being visible. - Get it: Identify where the people you call are, take the strictest applicable rule, and write down what you concluded. - Verify: A written note names the jurisdictions and the rule applied - [ ] **Your exclusion list, written before capture** · free - Why: A password manager, a private message window or a medical portal captured once is captured, and deciding the list afterwards is deciding it too late. - Get it: List applications and window title patterns that must never be captured. Err wide. - Verify: The list is loaded by the capture path before the first run - [ ] **A list of assessment and proctoring applications** · free - Why: Phase 3 refuses to operate in those contexts, and the check is only as good as the list. - Get it: Identify the proctoring and assessment tools in use where you are. Keep the list narrow so false positives stay rare, since there is no override. - Verify: A list exists and blocking is confirmed with at least one of them running ## Quick start Follow Phase 1 in `BUILD_PLAN.md`; it creates the project. Then copy `.env.example` to `.env` and fill in the values it documents. ## Honest limits This build deliberately does not replace: - Invisibility of any kind. - Use in interviews, exams and assessments. - Cloud storage of captures. - Real-time coaching during a live call. - Screen-share invisibility that has actually been tested against Zoom, Meet, Teams and OS screenshot tools - Sub-second latency and the prompt tuning that makes answers short enough to read while someone is talking - System audio capture that just works without you installing and routing a virtual audio device - Mobile and browser-extension coverage, plus a hosted account so your setup follows you to another machine - Somebody else's legal and PR exposure for a product whose pitch is 'cheat on everything' If one of those is essential to you, that is the reason to keep paying for Cluely, and the README should say so rather than pretend.
# Build brief · Cluely The one-shot brief this plan expands. `BUILD_PLAN.md` (or `MILESTONES.md`) is the same sequence broken into steps and checks; where the two disagree, the plan wins. Build me a desktop assistant that reads your screen and hears your calls, built to be disclosed to replace Cluely. Build it in phases, in the order below. Do not write the whole thing in one pass. Finish a phase, run its "Done when" check, fix what fails, and only then start the next phase. ### Rule zero This category is marketed around being invisible: an overlay that watches your screen and listens to your calls and feeds you answers, positioned for interviews, exams and sales calls where the other party does not know. Build the tool; do not build the invisibility. Two reasons, and neither is squeamishness. Undisclosed assistance in an interview or an assessment is misrepresentation, and it is the user who carries that, not the tool. And listening to a call means recording other people, which is governed by consent rules that attach to the recording regardless of whether anyone can see the software. So this build: has no screen-sharing evasion, no hidden-from-capture mode, no invisibility of any kind. It prompts to disclose when audio capture starts and records whether you did. It refuses to run in modes it can detect are assessments. Audio and screen capture are separately consented and separately indicated, with an indicator that cannot be turned off. The genuinely useful version of this is an assistant for your own work: your documents, your notes, your calls with consent. That version is worth building, and it is what follows. ### Stack (fixed, do not substitute) - Capture: Screen region capture and system audio, each separately permitted · they are different intrusions and deserve different consent - Processing: Local models by default, with any hosted call an explicit per-session choice · screen contents and call audio are the most sensitive things on a machine - Indication: An always-visible indicator that cannot be disabled · the whole ethical position rests on the capture being apparent - Retention: Short by default, with transcripts and screen text expiring separately · captured context loses value in minutes and stays sensitive for years - Runtime: A native overlay application with a hotkey · it has to be reachable without leaving what you are doing ### Data model (create this before Phase 1) - sessions(id, started_at, ended_at, screen_capture, audio_capture, disclosed_at, model_policy) - captures(id, session_id, kind, at, text, region_json, redacted) · kind is screen_text or transcript - exclusions(id, kind, pattern) · applications and window titles never captured, applied before writing - queries(id, session_id, prompt, response, model, at, capture_ids_json) · what context each answer used - consents(session_id, scope, granted_at, evidence) · screen and audio consented separately - assessment_blocks(id, detected_signal, at) · when the tool refused to run and why - A query records which captures it used, so you can always answer what the assistant saw when it said something. ### Phase 1 · Capture that announces itself Build: Screen and audio capture as separately requested permissions, each with its own visible indicator that cannot be hidden or disabled. Apply an exclusion list before writing anything. Make stopping capture immediate and obvious. Trap: Building an indicator that any setting can hide means the invisibility is one configuration change away, and the position that this tool is ethical rests entirely on it not being. Make the indicator part of the capture path, so capture without indication is not a state the application can reach. Done when: Capture cannot run without a visible indicator, verified by attempting to disable it in configuration and in code. Screen and audio are permitted separately. An excluded application produces no capture rows, verified by inspecting the store. Stopping capture takes effect immediately and the indicator clears. Do not build yet: No processing, queries or retention. ### Phase 2 · Disclosure when other people are involved Build: Prompt to disclose whenever audio capture begins, with suggested wording, and record whether disclosure happened. Mark sessions captured without disclosure. Provide no way to suppress the prompt permanently. Trap: A prompt with a do-not-ask-again option becomes a tool that silently records other people's conversations within a week, and the recording of that decision is a checkbox nobody remembers ticking. Prompt every time, keep the record, and make an undisclosed session visibly different from a disclosed one everywhere it appears. Done when: Audio capture prompts for disclosure every time it starts, with no permanent suppression available. Disclosure time is recorded when confirmed. An undisclosed session is marked in the session list and on any output derived from it. Screen capture alone does not prompt, since it involves nobody else. Do not build yet: No assistant queries yet. ### Phase 3 · Refusing the uses this should not have Build: Detect signals that the machine is in an assessment or interview context, such as known proctoring or assessment applications being in the foreground, and refuse to answer queries. Record the refusal. Provide no override. Trap: Detection here will be imperfect in both directions, and the temptation is to add an override for the false positives, which immediately makes the whole check optional. Accept the false positives, keep the check narrow enough that they are rare, and treat someone needing an override as a signal about the use rather than a gap to fill. Done when: A known assessment application in the foreground causes queries to be refused with a clear explanation. The refusal is recorded. No override exists, verified by looking for one. The detection list is a configuration file that can be extended but not emptied at runtime. Do not build yet: No local processing or retention yet. ### Phase 4 · Answers from context, kept local Build: Answer queries using recent captures, recording which captures each answer used. Run locally by default with any hosted model an explicit per-session choice. Show the context used alongside every answer. Trap: Sending the whole capture buffer to a hosted model on every query ships screen contents and call transcripts to a third party continuously, including from the sessions where you excluded an application but had it in the buffer from before. Select context deliberately, show what was sent, and make hosted use a per-session decision rather than a preference. Done when: Every answer shows which captures it used. Local processing is the default and a hosted model requires a per-session choice, verified by checking that no request leaves without one. Excluded content never enters the context, tested by excluding an application mid-session. The context sent to a hosted model is displayed before sending. Do not build yet: No retention or export yet. ### Phase 5 · Forgetting quickly Build: Short retention for screen text and transcripts, with disclosure records kept longer. Deletion removing captures, queries and their context references. Verify no capture text reaches logs or crash reports. Trap: Screen text and call transcripts in a log or a crash report leak exactly the material the whole design was protecting, and they get added by someone making debugging easier. Assert it in the test suite: scan every log and report path for capture fields and fail the build if any appear. Done when: Screen text and transcripts expire on a short retention while disclosure records survive. A test fails when a capture field is added to a log path, verified by deliberately adding one. Deletion removes captures, queries and context references together. Retention runs whether or not the application is open. Do not build yet: Nothing after this. ### Out of scope (and why) - Any invisibility: hiding from screen sharing, from capture, or from the people in the room. Its absence is the reason this build is defensible. - Use in interviews, exams and assessments, which the build actively refuses rather than merely discourages. - Cloud storage of captures, which would turn a local tool into a database of everything on your screen. - Real-time coaching during a live call, which is the positioning that makes the category what it is. ### README must contain - That there is no invisibility of any kind and why that is the design rather than an omission - That the capture indicator is part of the capture path and cannot be disabled - That audio capture prompts for disclosure every time with no permanent suppression - That assessment contexts block queries and there is no override - That captures expire quickly and a test asserts they never reach a log
# Agent instructions · Cluely indie build - Read `README.md` and `BUILD_PLAN.md` before writing code. The stack is fixed: Screen region capture and system audio, each separately permitted, Local models by default, with any hosted call an explicit per-session choice, An always-visible indicator that cannot be disabled, Short by default, with transcripts and screen text expiring separately, A native overlay application with a hotkey. Do not substitute. - Work one phase at a time, in order. Do not start a phase until every "Done when" item of the previous one passes. - Prefer the fewest moving parts that satisfy the step. No frameworks, services or dependencies the plan does not name. - Secrets live in `.env`, never in source or logs. Keep `.env.example` current when a variable is introduced. - Do not invent cryptography, security guarantees, APIs or compliance claims. - Add a focused test for every destructive, security-sensitive or data-loss path the plan names. - Run the project checks before declaring a phase complete, and record any deliberate shortcut in the README under "Tradeoffs". ## Known traps - Building an indicator that any setting can hide means the invisibility is one configuration change away, and the position that this tool is ethical rests entirely on it not being. Make the indicator part of the capture path, so capture without indication is not a state the application can reach. - A prompt with a do-not-ask-again option becomes a tool that silently records other people's conversations within a week, and the recording of that decision is a checkbox nobody remembers ticking. Prompt every time, keep the record, and make an undisclosed session visibly different from a disclosed one everywhere it appears. - Detection here will be imperfect in both directions, and the temptation is to add an override for the false positives, which immediately makes the whole check optional. Accept the false positives, keep the check narrow enough that they are rare, and treat someone needing an override as a signal about the use rather than a gap to fill. - Sending the whole capture buffer to a hosted model on every query ships screen contents and call transcripts to a third party continuously, including from the sessions where you excluded an application but had it in the buffer from before. Select context deliberately, show what was sent, and make hosted use a per-session decision rather than a preference.
# Build plan · Cluely A desktop assistant with access to what is on your screen and, with consent, what is said on your calls, where the engineering is in capturing selectively and locally, and the design is entirely about the capture being visible to everyone it affects. Phases are in dependency order. Each ends in a "Done when" list; treat an unticked item as a blocker, not a note. ## Phase 1 · Capture that announces itself Nobody near this machine could be unaware that capture is running. ### Steps 1. Tie the indicator to the capture path Capture without indication should not be a reachable state. Files: `src/Indicator.swift` 2. Permit screen and audio separately Different intrusions. Bundling them makes both harder to refuse. Files: `src/Permissions.swift` 3. Apply exclusions before writing A password manager or a private message window should never reach disk. Files: `src/Exclusions.swift` ### Done when - [ ] Capture cannot run without a visible indicator - [ ] Screen and audio permissions are separate - [ ] Excluded applications produce no rows - [ ] Stopping capture is immediate and visible ### Watch out - Building an indicator that any setting can hide means the invisibility is one configuration change away, and the position that this tool is ethical rests entirely on it not being. Make the indicator part of the capture path, so capture without indication is not a state the application can reach. ## Phase 2 · Disclosure when other people are involved Starting audio capture prompts you to tell the people on the call. ### Steps 1. Prompt on every audio capture start Every time. A remembered answer is not consent from the people on the call. Files: `src/Disclosure.swift` 2. Offer wording to use One sentence. Making it easy is what makes it happen. Files: `config/disclosure.md` 3. Mark undisclosed sessions everywhere In the list and on anything derived from them. Files: `src/Sessions.swift` ### Done when - [ ] Audio capture prompts every time - [ ] No permanent suppression exists - [ ] Undisclosed sessions are marked everywhere - [ ] Screen-only capture does not prompt ### Watch out - A prompt with a do-not-ask-again option becomes a tool that silently records other people's conversations within a week, and the recording of that decision is a checkbox nobody remembers ticking. Prompt every time, keep the record, and make an undisclosed session visibly different from a disclosed one everywhere it appears. ## Phase 3 · Refusing the uses this should not have The tool declines to operate as undisclosed assistance in an assessment. ### Steps 1. Detect narrow, well-known signals Narrow enough that false positives are rare, since there is no override. Files: `src/Assessment.swift` 2. Refuse and explain Not silently degrade. The user should know why. Files: `src/Query.swift` 3. Provide no override Its absence is the point. An override makes the check decorative. Files: `src/Assessment.swift` ### Done when - [ ] A known assessment application blocks queries - [ ] The refusal is explained and recorded - [ ] No override exists - [ ] The detection list cannot be emptied at runtime ### Watch out - Detection here will be imperfect in both directions, and the temptation is to add an override for the false positives, which immediately makes the whole check optional. Accept the false positives, keep the check narrow enough that they are rare, and treat someone needing an override as a signal about the use rather than a gap to fill. ## Phase 4 · Answers from context, kept local The assistant uses what it captured and you know exactly what it saw. ### Steps 1. Record the context per query Which captures. So you can answer what it saw. Files: `src/Query.swift` 2. Make hosted use per session Not a preference. A preference is set once and forgotten. Files: `src/ModelPolicy.swift` 3. Show what is sent before sending Screen contents leaving the machine deserves a look first. Files: `src/Review.swift` ### Done when - [ ] Every answer shows the captures it used - [ ] Local is default and hosted is per session - [ ] Excluded content never enters context - [ ] Context is shown before leaving the machine ### Watch out - Sending the whole capture buffer to a hosted model on every query ships screen contents and call transcripts to a third party continuously, including from the sessions where you excluded an application but had it in the buffer from before. Select context deliberately, show what was sent, and make hosted use a per-session decision rather than a preference. ## Not in this build - Invisibility of any kind. - Use in interviews, exams and assessments. - Cloud storage of captures. - Real-time coaching during a live call. ## After v1, if you want it - Answering from your own documents rather than only from what is on screen - A session summary you can keep after the captures expire - Per-application context rules, so a code editor and a browser are treated differently
# Copy to .env and fill in. Never commit .env; this file documents it. # Required. Screen text and transcripts. The most sensitive file this build produces. DB_PATH=~/.local/share/assistant/captures.db # Required · secret. Encrypts the capture store at rest. DB_KEY=a keychain reference # Required. Present as a constant so the answer is visible. Capture without indication is not a reachable state. INDICATOR_DISABLE=impossible # Required. How long captures live. Minutes, because that is how long they are useful. CAPTURE_RETENTION_MINUTES=60 # Required. Much longer than the capture, because it is the evidence. DISCLOSURE_RETENTION_DAYS=1825 # Required. Loaded by the capture path before the first write, not applied at display. EXCLUSIONS_PATH=./config/exclusions.txt
# Cluely · product brief ## Problem The core loop is genuinely thin: capture a screenshot, transcribe the mic, feed both to a multimodal model, stream the answer into a transparent always-on-top window on a hotkey. An agent gets that working in a session, and it will feel uncomfortably close to the demo. The gaps are the unglamorous parts: capturing the other side's audio takes virtual audio devices, latency has to beat the conversation, and the headline trick of staying invisible in screen shares depends on fragile platform window flags that vary by OS and conferencing app. Your DIY version will work fine when you are alone with your own screen, and may quietly betray you the one time it matters. ## Product outcome An assistant that can see your screen and hear your calls, where everyone affected can tell that it is running, and which refuses the uses that made the category notorious. ## Target user A builder who needs a maintainable product foundation, not a one-off demo. ## Required capabilities - An OpenAI API key (or any multimodal chat endpoint) in .env - macOS or Windows desktop, plus screen recording and microphone permissions - A virtual audio device for other-party audio: BlackHole on macOS, VB-Cable or WASAPI loopback on Windows - Node 20 and willingness to sign or self-trust an unsigned Electron build ## Explicit non-goals for v1 - Invisibility of any kind. - Use in interviews, exams and assessments. - Cloud storage of captures. - Real-time coaching during a live call. - Screen-share invisibility that has actually been tested against Zoom, Meet, Teams and OS screenshot tools - Sub-second latency and the prompt tuning that makes answers short enough to read while someone is talking - System audio capture that just works without you installing and routing a virtual audio device - Mobile and browser-extension coverage, plus a hosted account so your setup follows you to another machine - Somebody else's legal and PR exposure for a product whose pitch is 'cheat on everything' ## Success criteria - Capture without a visible indicator is confirmed unreachable - Audio capture is confirmed to prompt every time - An assessment context is confirmed to block queries with no override - Excluded content is confirmed never to enter context - The suite is confirmed to fail when a capture field reaches a log
# Build brief · Cluely The one-shot brief this plan expands. `BUILD_PLAN.md` (or `MILESTONES.md`) is the same sequence broken into steps and checks; where the two disagree, the plan wins. Build me a desktop assistant that reads your screen and hears your calls, built to be disclosed to replace Cluely. Build it in phases, in the order below. Do not write the whole thing in one pass. Finish a phase, run its "Done when" check, fix what fails, and only then start the next phase. ### Rule zero This category is marketed around being invisible: an overlay that watches your screen and listens to your calls and feeds you answers, positioned for interviews, exams and sales calls where the other party does not know. Build the tool; do not build the invisibility. Two reasons, and neither is squeamishness. Undisclosed assistance in an interview or an assessment is misrepresentation, and it is the user who carries that, not the tool. And listening to a call means recording other people, which is governed by consent rules that attach to the recording regardless of whether anyone can see the software. So this build: has no screen-sharing evasion, no hidden-from-capture mode, no invisibility of any kind. It prompts to disclose when audio capture starts and records whether you did. It refuses to run in modes it can detect are assessments. Audio and screen capture are separately consented and separately indicated, with an indicator that cannot be turned off. The genuinely useful version of this is an assistant for your own work: your documents, your notes, your calls with consent. That version is worth building, and it is what follows. ### Stack (fixed, do not substitute) - Capture: Screen region capture and system audio, each separately permitted · they are different intrusions and deserve different consent - Processing: Local models by default, with any hosted call an explicit per-session choice · screen contents and call audio are the most sensitive things on a machine - Indication: An always-visible indicator that cannot be disabled · the whole ethical position rests on the capture being apparent - Retention: Short by default, with transcripts and screen text expiring separately · captured context loses value in minutes and stays sensitive for years - Runtime: A native overlay application with a hotkey · it has to be reachable without leaving what you are doing ### Data model (create this before Phase 1) - sessions(id, started_at, ended_at, screen_capture, audio_capture, disclosed_at, model_policy) - captures(id, session_id, kind, at, text, region_json, redacted) · kind is screen_text or transcript - exclusions(id, kind, pattern) · applications and window titles never captured, applied before writing - queries(id, session_id, prompt, response, model, at, capture_ids_json) · what context each answer used - consents(session_id, scope, granted_at, evidence) · screen and audio consented separately - assessment_blocks(id, detected_signal, at) · when the tool refused to run and why - A query records which captures it used, so you can always answer what the assistant saw when it said something. ### Phase 1 · Capture that announces itself Build: Screen and audio capture as separately requested permissions, each with its own visible indicator that cannot be hidden or disabled. Apply an exclusion list before writing anything. Make stopping capture immediate and obvious. Trap: Building an indicator that any setting can hide means the invisibility is one configuration change away, and the position that this tool is ethical rests entirely on it not being. Make the indicator part of the capture path, so capture without indication is not a state the application can reach. Done when: Capture cannot run without a visible indicator, verified by attempting to disable it in configuration and in code. Screen and audio are permitted separately. An excluded application produces no capture rows, verified by inspecting the store. Stopping capture takes effect immediately and the indicator clears. Do not build yet: No processing, queries or retention. ### Phase 2 · Disclosure when other people are involved Build: Prompt to disclose whenever audio capture begins, with suggested wording, and record whether disclosure happened. Mark sessions captured without disclosure. Provide no way to suppress the prompt permanently. Trap: A prompt with a do-not-ask-again option becomes a tool that silently records other people's conversations within a week, and the recording of that decision is a checkbox nobody remembers ticking. Prompt every time, keep the record, and make an undisclosed session visibly different from a disclosed one everywhere it appears. Done when: Audio capture prompts for disclosure every time it starts, with no permanent suppression available. Disclosure time is recorded when confirmed. An undisclosed session is marked in the session list and on any output derived from it. Screen capture alone does not prompt, since it involves nobody else. Do not build yet: No assistant queries yet. ### Phase 3 · Refusing the uses this should not have Build: Detect signals that the machine is in an assessment or interview context, such as known proctoring or assessment applications being in the foreground, and refuse to answer queries. Record the refusal. Provide no override. Trap: Detection here will be imperfect in both directions, and the temptation is to add an override for the false positives, which immediately makes the whole check optional. Accept the false positives, keep the check narrow enough that they are rare, and treat someone needing an override as a signal about the use rather than a gap to fill. Done when: A known assessment application in the foreground causes queries to be refused with a clear explanation. The refusal is recorded. No override exists, verified by looking for one. The detection list is a configuration file that can be extended but not emptied at runtime. Do not build yet: No local processing or retention yet. ### Phase 4 · Answers from context, kept local Build: Answer queries using recent captures, recording which captures each answer used. Run locally by default with any hosted model an explicit per-session choice. Show the context used alongside every answer. Trap: Sending the whole capture buffer to a hosted model on every query ships screen contents and call transcripts to a third party continuously, including from the sessions where you excluded an application but had it in the buffer from before. Select context deliberately, show what was sent, and make hosted use a per-session decision rather than a preference. Done when: Every answer shows which captures it used. Local processing is the default and a hosted model requires a per-session choice, verified by checking that no request leaves without one. Excluded content never enters the context, tested by excluding an application mid-session. The context sent to a hosted model is displayed before sending. Do not build yet: No retention or export yet. ### Phase 5 · Forgetting quickly Build: Short retention for screen text and transcripts, with disclosure records kept longer. Deletion removing captures, queries and their context references. Verify no capture text reaches logs or crash reports. Trap: Screen text and call transcripts in a log or a crash report leak exactly the material the whole design was protecting, and they get added by someone making debugging easier. Assert it in the test suite: scan every log and report path for capture fields and fail the build if any appear. Done when: Screen text and transcripts expire on a short retention while disclosure records survive. A test fails when a capture field is added to a log path, verified by deliberately adding one. Deletion removes captures, queries and context references together. Retention runs whether or not the application is open. Do not build yet: Nothing after this. ### Out of scope (and why) - Any invisibility: hiding from screen sharing, from capture, or from the people in the room. Its absence is the reason this build is defensible. - Use in interviews, exams and assessments, which the build actively refuses rather than merely discourages. - Cloud storage of captures, which would turn a local tool into a database of everything on your screen. - Real-time coaching during a live call, which is the positioning that makes the category what it is. ### README must contain - That there is no invisibility of any kind and why that is the design rather than an omission - That the capture indicator is part of the capture path and cannot be disabled - That audio capture prompts for disclosure every time with no permanent suppression - That assessment contexts block queries and there is no override - That captures expire quickly and a test asserts they never reach a log
# Architecture · Cluely ## Stack | Part | Choice | Why | | --- | --- | --- | | Capture | Screen region capture and system audio, each separately permitted | they are different intrusions and deserve different consent | | Processing | Local models by default, with any hosted call an explicit per-session choice | screen contents and call audio are the most sensitive things on a machine | | Indication | An always-visible indicator that cannot be disabled | the whole ethical position rests on the capture being apparent | | Retention | Short by default, with transcripts and screen text expiring separately | captured context loses value in minutes and stays sensitive for years | | Runtime | A native overlay application with a hotkey | it has to be reachable without leaving what you are doing | ## Modules Each module has one owner concern and a documented way to replace it. | Module | Owns | How to replace it | | --- | --- | --- | | Capture | Screen and audio, separately permitted and indicated. | Any implementation, provided the indicator is inseparable from capture. | | Disclosure | Prompting and recording for audio sessions. | Not swappable for a remembered preference, which is not consent from the other party. | | Refusal | Blocking in assessment contexts. | Any detection, provided no override exists. | | Context | Selecting and recording what each answer used. | Any selection, provided it is shown before anything leaves the machine. | | Retention | Short expiry and log exclusion. | Any policy, provided the log assertion stays in the suite. | ## Configuration Every runtime setting is an environment variable documented in `.env.example`, validated at startup, with a safe local default wherever one exists. - `DB_PATH` · required · Screen text and transcripts. The most sensitive file this build produces. - `DB_KEY` · required, secret · Encrypts the capture store at rest. - `INDICATOR_DISABLE` · required · Present as a constant so the answer is visible. Capture without indication is not a reachable state. - `CAPTURE_RETENTION_MINUTES` · required · How long captures live. Minutes, because that is how long they are useful. - `DISCLOSURE_RETENTION_DAYS` · required · Much longer than the capture, because it is the evidence. - `EXCLUSIONS_PATH` · required · Loaded by the capture path before the first write, not applied at display. ## Production baseline - Security: least privilege, input validation at every boundary, secret redaction in logs, rate limits on abuse-prone paths, no invented security primitives. - Data: explicit schema and migrations, transactional writes where integrity matters, backup and restore procedures that have been exercised. - Integrations: adapters around third-party providers, idempotent webhook or job processing, bounded retries, timeouts. - Observability: structured logs with request or operation ids, an error-tracking hook, and health and readiness checks where a server exists. - Quality: unit tests for domain rules, integration tests at module boundaries, one end-to-end test of the critical path. ## Decision records For each dependency in the stack table, keep a short note: why it was chosen, its failure mode, and how it is replaced. Do not add infrastructure until a requirement in `PRODUCT.md` justifies it.
# Agent instructions · Cluely product build - Read `PRODUCT.md` and `ARCHITECTURE.md` before changing code. The stack is fixed: Screen region capture and system audio, each separately permitted, Local models by default, with any hosted call an explicit per-session choice, An always-visible indicator that cannot be disabled, Short by default, with transcripts and screen text expiring separately, A native overlay application with a hotkey. - Implement milestone by milestone from `MILESTONES.md`; keep each change reviewable and leave the application runnable at every commit. - Treat authentication, payments, encryption, imports, webhooks and destructive actions as high-risk boundaries when present. - Never invent cryptography or silently weaken a requirement to make a check pass. - Put every external service behind an interface with a deterministic fake for tests. - Add migrations and rollback or recovery notes for every persistent data change. - Log useful operational context without credentials, tokens, passwords or personal data. - Update documentation and run every check before completing a milestone. ## Known traps - Building an indicator that any setting can hide means the invisibility is one configuration change away, and the position that this tool is ethical rests entirely on it not being. Make the indicator part of the capture path, so capture without indication is not a state the application can reach. - A prompt with a do-not-ask-again option becomes a tool that silently records other people's conversations within a week, and the recording of that decision is a checkbox nobody remembers ticking. Prompt every time, keep the record, and make an undisclosed session visibly different from a disclosed one everywhere it appears. - Detection here will be imperfect in both directions, and the temptation is to add an override for the false positives, which immediately makes the whole check optional. Accept the false positives, keep the check narrow enough that they are rare, and treat someone needing an override as a signal about the use rather than a gap to fill. - Sending the whole capture buffer to a hosted model on every query ships screen contents and call transcripts to a third party continuously, including from the sessions where you excluded an application but had it in the buffer from before. Select context deliberately, show what was sent, and make hosted use a per-session decision rather than a preference. - Screen text and call transcripts in a log or a crash report leak exactly the material the whole design was protecting, and they get added by someone making debugging easier. Assert it in the test suite: scan every log and report path for capture fields and fail the build if any appear.
# Delivery milestones · Cluely Estimated effort: **multi-day** for the indie phases; the production-only milestones add the trust and operability layer. ## M1 · Capture that announces itself Nobody near this machine could be unaware that capture is running. ### Steps 1. Tie the indicator to the capture path Capture without indication should not be a reachable state. Files: `src/Indicator.swift` 2. Permit screen and audio separately Different intrusions. Bundling them makes both harder to refuse. Files: `src/Permissions.swift` 3. Apply exclusions before writing A password manager or a private message window should never reach disk. Files: `src/Exclusions.swift` ### Done when - [ ] Capture cannot run without a visible indicator - [ ] Screen and audio permissions are separate - [ ] Excluded applications produce no rows - [ ] Stopping capture is immediate and visible ### Watch out - Building an indicator that any setting can hide means the invisibility is one configuration change away, and the position that this tool is ethical rests entirely on it not being. Make the indicator part of the capture path, so capture without indication is not a state the application can reach. ## M2 · Disclosure when other people are involved Starting audio capture prompts you to tell the people on the call. ### Steps 1. Prompt on every audio capture start Every time. A remembered answer is not consent from the people on the call. Files: `src/Disclosure.swift` 2. Offer wording to use One sentence. Making it easy is what makes it happen. Files: `config/disclosure.md` 3. Mark undisclosed sessions everywhere In the list and on anything derived from them. Files: `src/Sessions.swift` ### Done when - [ ] Audio capture prompts every time - [ ] No permanent suppression exists - [ ] Undisclosed sessions are marked everywhere - [ ] Screen-only capture does not prompt ### Watch out - A prompt with a do-not-ask-again option becomes a tool that silently records other people's conversations within a week, and the recording of that decision is a checkbox nobody remembers ticking. Prompt every time, keep the record, and make an undisclosed session visibly different from a disclosed one everywhere it appears. ## M3 · Refusing the uses this should not have The tool declines to operate as undisclosed assistance in an assessment. ### Steps 1. Detect narrow, well-known signals Narrow enough that false positives are rare, since there is no override. Files: `src/Assessment.swift` 2. Refuse and explain Not silently degrade. The user should know why. Files: `src/Query.swift` 3. Provide no override Its absence is the point. An override makes the check decorative. Files: `src/Assessment.swift` ### Done when - [ ] A known assessment application blocks queries - [ ] The refusal is explained and recorded - [ ] No override exists - [ ] The detection list cannot be emptied at runtime ### Watch out - Detection here will be imperfect in both directions, and the temptation is to add an override for the false positives, which immediately makes the whole check optional. Accept the false positives, keep the check narrow enough that they are rare, and treat someone needing an override as a signal about the use rather than a gap to fill. ## M4 · Answers from context, kept local The assistant uses what it captured and you know exactly what it saw. ### Steps 1. Record the context per query Which captures. So you can answer what it saw. Files: `src/Query.swift` 2. Make hosted use per session Not a preference. A preference is set once and forgotten. Files: `src/ModelPolicy.swift` 3. Show what is sent before sending Screen contents leaving the machine deserves a look first. Files: `src/Review.swift` ### Done when - [ ] Every answer shows the captures it used - [ ] Local is default and hosted is per session - [ ] Excluded content never enters context - [ ] Context is shown before leaving the machine ### Watch out - Sending the whole capture buffer to a hosted model on every query ships screen contents and call transcripts to a third party continuously, including from the sessions where you excluded an application but had it in the buffer from before. Select context deliberately, show what was sent, and make hosted use a per-session decision rather than a preference. ## M5 · Forgetting quickly (production only) Captured context expires fast and deletion is complete. ### Steps 1. Expire captures quickly Their value is minutes. Their sensitivity is years. Files: `src/Retention.swift` 2. Keep disclosure records longer They are the evidence the capture was disclosed. Files: `src/Retention.swift` 3. Assert captures never reach logs In the suite, with a deliberately added field to prove the check works. Files: `tests/NoCaptureInLogsTests.swift` ### Done when - [ ] Captures expire while disclosure records survive - [ ] The suite fails when a capture field reaches a log - [ ] Deletion removes captures, queries and references - [ ] Retention runs without the application open ### Watch out - Screen text and call transcripts in a log or a crash report leak exactly the material the whole design was protecting, and they get added by someone making debugging easier. Assert it in the test suite: scan every log and report path for capture fields and fail the build if any appear.
# Operations · Cluely ## Backup Captures should mostly not be backed up at all, since they expire in an hour and are the most sensitive data here. Disclosure records are the thing worth retaining, and they are small. ## Restore Restore and confirm retention resumes immediately, since restoring expired captures recreates exactly the material the short retention exists to remove. Do a restore drill before the first real user, and write the date here when it passes. ## Monitoring Undisclosed session count is the number that matters. A rising count means the disclosure prompt is being dismissed, which is a use question rather than a technical one. ## Incident checklist Capture text appearing in a log or crash report is the incident, and the suite assertion is the control. If it was removed to make debugging easier, that is the change to revert rather than the finding to explain. 1. Contain the issue without destroying evidence or user data. 2. Record the timeline and affected scope. 3. Rotate exposed secrets and revoke compromised sessions or credentials. 4. Restore from a verified backup when needed. 5. Document the root cause, the remediation and the regression test. ## Release gate - [ ] Capture without a visible indicator is confirmed unreachable - [ ] Audio capture is confirmed to prompt every time - [ ] An assessment context is confirmed to block queries with no override - [ ] Excluded content is confirmed never to enter context - [ ] The suite is confirmed to fail when a capture field reaches a log ## Launch constraint Do not market omitted Cluely capabilities as implemented. The non-goals in `PRODUCT.md` remain user-visible limitations until they are deliberately delivered.
# Copy to .env and fill in. Never commit .env; this file documents it. # Required. Screen text and transcripts. The most sensitive file this build produces. DB_PATH=~/.local/share/assistant/captures.db # Required · secret. Encrypts the capture store at rest. DB_KEY=a keychain reference # Required. Present as a constant so the answer is visible. Capture without indication is not a reachable state. INDICATOR_DISABLE=impossible # Required. How long captures live. Minutes, because that is how long they are useful. CAPTURE_RETENTION_MINUTES=60 # Required. Much longer than the capture, because it is the evidence. DISCLOSURE_RETENTION_DAYS=1825 # Required. Loaded by the capture path before the first write, not applied at display. EXCLUSIONS_PATH=./config/exclusions.txt
$ choose a build depth, inspect the files, then open the complete pack in your agent
Because the hard part is not the LLM call, it is the twenty small platform details that make an overlay silent, invisible and fast under pressure, and because people who reach for this tool are, by definition, not in the mood to debug a virtual audio driver ten minutes before an interview. Paying converts a fragile personal hack into something that mostly behaves on a laptop you did not configure yourself.
xScreen-share invisibility that has actually been tested against Zoom, Meet, Teams and OS screenshot tools
xSub-second latency and the prompt tuning that makes answers short enough to read while someone is talking
xSystem audio capture that just works without you installing and routing a virtual audio device
xMobile and browser-extension coverage, plus a hosted account so your setup follows you to another machine
xSomebody else's legal and PR exposure for a product whose pitch is 'cheat on everything'
Nothing worth pointing at. That's why the prompt exists.
Vibecode Cluely
Kinda. The core of Cluely is buildable in a weekend with the prompt on this page, but there are real gaps: Screen-share invisibility that has actually been tested against Zoom, Meet, Teams and OS screenshot tools, Sub-second latency and the prompt tuning that makes answers short enough to read while someone is talking. Read the honest list above before committing.
How much does Cluely cost?
Cluely costs about $19.99/month (Pro, checked 2026-08-16), which is $239.88 per year.
What do I lose by replacing Cluely?
Honestly: Screen-share invisibility that has actually been tested against Zoom, Meet, Teams and OS screenshot tools; Sub-second latency and the prompt tuning that makes answers short enough to read while someone is talking; System audio capture that just works without you installing and routing a virtual audio device; Mobile and browser-extension coverage, plus a hosted account so your setup follows you to another machine; Somebody else's legal and PR exposure for a product whose pitch is 'cheat on everything'. If any of those are load-bearing for you, keep paying.
Is there an open-source alternative to Cluely?
No mature open-source alternative worth pointing at, which is exactly why the one-shot prompt on this page exists.