Javis OS
Javis OS는 기업가를 돕는 에이전시 AI로, 업무를 지원하고 함께 성장합니다
연락처 목록을 영업 흐름으로 전환하고 브리프·데이터 충돌 해결·후속 관리까지 ProspectPilot으로
Turn your existing contact lists into a clear prospecting workflow. Prepare briefs, resolve data conflicts, and keep follow-ups moving with ProspectPilot.
비즈니스JavaScript · HTMLGitHub @dst-boop온라인운영자 미확인
써 보셨어요? 한 번만 눌러 주세요. 로그인은 필요 없어요.
아직 감지된 업데이트가 없습니다. GitHub 릴리스가 나오면 여기에 보입니다.
개인 계정의 공개 저장소 소유자는 GitHub로 로그인해 운영자를 확인하고 소개를 직접 관리할 수 있습니다. 관리자 승인은 필요하지 않습니다.
로그인한 뒤 확인 파일을 만들어 이 저장소의 기본 브랜치에 30분 안에 커밋해 주세요. 다른 브랜치나 포크의 파일은 인정하지 않습니다. 파일을 올린 뒤 아래에서 확인하면 관리자 승인 없이 관리할 수 있습니다. 자격을 유지하려면 파일을 남겨 두세요.
로그인이 필요하면 로그인 화면으로 이동합니다. 로그인 후 이곳으로 돌아와 원하는 확인 버튼을 다시 눌러 주세요.
프로젝트 폴더에서 /nomorevibe verify를 실행하면 소유권을 확인하고 소개를 직접 관리할 수 있습니다.
1분 만에 확인하기README 전체를 불러오는 중입니다. 아래는 저장된 발췌입니다.
An advisor workspace for choosing the next prospect, reviewing evidence, and keeping follow-ups moving, alongside a professional contact directory and research tools. Built on the existing Firebase-authenticated Cloud Run and Cloud SQL application.README 전문 보기 ↗An advisor workspace for choosing the next prospect, reviewing evidence, and keeping follow-ups moving, alongside a professional contact directory and research tools. Built on the existing Firebase-authenticated Cloud Run and Cloud SQL application.
Visitors see a public homepage explaining the workflow, data sources, and product limits. The authenticated home page opens the advisor worklist with a direct next-prospect action and shortcuts to imports, due follow-ups, and evidence reviews. /prospect continues to provide directory filters, CSV import with deduplication, lists, saved searches, contact details, source and verification history, suppression controls, and CSV export. People Data Labs search/enrichment and Hunter verification run through background jobs with progress, explicit cost ceilings and shared daily budget reservations. Phone numbers remain provider-reported and unverified; email verification expires after 30 days.
Selected source: ZoomInfo CSV exports, without API access. Import an authorized export using the ZoomInfo preset, then manage and export the contact list. Automated API search/enrichment and independent email verification are optional separate integrations. See provider setup for credentials, provider entitlements, pricing and worker configuration. No provider subscription or proprietary contact database is bundled. The app supports public account creation with Google or email/password. Email addresses must be verified before accessing a workspace. Contacts, lists, jobs and exports are isolated by Firebase user ID. OWNER_EMAIL designates the administrator for older tools; it is not a signup allowlist. Configure Firebase sign-in providers for each deployment.
The home page and /lab prioritize overdue follow-ups, prospects with reviewed age/residence/contact evidence, and the next missing evidence task. Open a prospect for its conversation brief, verified contact shortcut, outcome log, and next follow-up time. The existing daily discovery and source economics controls remain under the expandable research section.
Select directory contacts and choose Add to advisor worklist to reuse their professional identifiers without a CSV round trip (100 at a time). This does not verify their qualification. Directory suppression is honored in linked research records; Do not contact in the worklist also suppresses linked directory contacts. Other directory corrections can be brought across by adding the contacts again; financial evidence is never inferred.
Conversation and meeting counters reflect manually logged outcomes over seven rolling days, not sent messages or calendar attendance. Meeting counts deduplicate people. A worklist scan is capped at 2,000 candidates; larger directories show a scope notice and can be narrowed by name/company search.
See the advisor workflow release for the short usage flow and deployment status.
Campaigns by place. Under the research tools, enter a ZIP code or town, a radius and business types (for example 11747, 25 miles, electrical contractors), and optionally the titles to keep (Owner, President, VP). The worker first finds companies in OpenStreetMap's free business directory and saves them with the run, then researches each company's own pages and SEC filings for people. Only people whose title matches are stored; the others are counted, not kept. Run details list every company found and why any were passed over (the run's company limit, or researched in the last seven days, so a daily campaign moves through the area). Leave the place blank to research named employers or the plan catalog as before. Each discovery run's details open with Where candidates went: companies found, researched, pages read, people found, matched the titles, saved, promising and fully confirmed, with the reasons the rest stopped at each stage (for example site blocks automated reading, daily budget reached, other titles, not kept). The counts are what the run recorded, not estimates. When a company's own links lead to nobody, research tries the usual team addresses (/leadership, /our-team, /about and similar) once, and if still nobody is found, up to three recent articles from the free GDELT news index that name the company. Every page, guessed or linked, is checked against the publisher's robots.txt. A person in a news article is credited to the company only when the sentence itself ties their role to it (for example Robin Hale is the president of Harbor Electrical or Harbor Electrical president Robin Hale), and the article's site is never recorded as the company's website. Findings from news are labelled News article.
Evidence that never overwrites. For title, employer, location, reported age, email, phones, LinkedIn and company website, every value a source reports is kept on the research record with its source and when it was first and last seen. The working value is the strongest source's (licensed export or reviewed, then regulatory filing, imported list, company website, news, web search), the newest among equals. When sources disagree, the lead shows Where sources disagree with each value, its source and dates; nothing is resolved behind the advisor's back, and "Delete this person" removes the history with the record.
Each weekday morning a scheduled Claude routine runs .claude/skills/daily-leads. By 8:00 a.m. ET it delivers likely-rollover prospects, each with a mobile number in hand (the advisor chooses how many ZoomInfo enrichments to spend a day): a ProspectPilot CSV in the Lead Qualifier shared drive and a digest email.
scripts/daily-leads/. Targeting is set in config.json.The qualification gates decide whether someone may be approached. This decides how often, and writes the next message.
Six touches in any rolling 45 days, counting email, phone and LinkedIn together. Reaching the limit opens a mandatory 90-day rest, recorded against the prospect with the reason, and the worklist shows them under Resting until it ends — a saved follow-up date does not make a resting prospect look due. A rest survives its touches ageing out of the 45-day window, so waiting does not quietly restore contact.
The budget belongs to the prospect, not to you. Six touches means this person is approached six times, however many advisors are working the list. The history and the rest period are read across the whole record, so a prospect a colleague has already spent the budget on is shown to you as resting rather than ready, and the worklist cannot offer them. When touches in force were somebody else's, the record says so by name — a prospect who rests for reasons you cannot see invites exactly the workaround the limit exists to prevent. Entries a colleague logged are marked with their name in the history. The daily dial limit stays yours alone, because that one protects a phone line's reputation rather than the person.
A prospect who responds leaves the sequence immediately, and the budget restarts from their reply: a reply ends the script, it does not buy an unlimited number of further approaches. Six unanswered touches after a reply reach the limit like any other six. When a rest period ends, the previous cycle ends with it and the prospect returns at the first step rather than arriving already finished.
Pacing bounds the approaches you make, not the ones they make. Tick They contacted me when recording a call or reply the prospect started. It is not one of the six touches, it spends none of the day's dials — it left from their number, not yours — and it ends a running rest: they asked to talk, so the reason for the rest is gone. The rest period is expired rather than deleted, so the row still marks where the next cycle starts. Only Connected, Follow-up agreed and Meeting booked can be inbound; a missed call from them is not an event, and a meeting is mutual by the time it is held. A contact restriction is not a pacing question and still refuses the save whoever placed the call — resolve the restriction first, then record what happened.
The next touch arrives written. Open a prospect and the brief carries the actual message for the step that is due — subject and body for an email, the script for a voicemail, the note for a connection request — composed from the saved record and signed from Your details. A fact that is not on file is named rather than left as a bracket in a sent message. Nothing is sent from the application.
A draft asserts only what the record establishes. It knows a name, an employer, and a previously reported employer. It does not know that anyone changed jobs recently, that they hold anything anywhere, or what a review would find — so it congratulates nothing, and a plan is always named as a condition ("if you still have a retirement plan with a former employer, such as from your time at X"), never as an account that exists. The voicemail script refers to the opening email only when the log shows it was sent. A test asserts this across every template, not only the ones written so far.
The schedule is kept for you. Logging an unanswered touch sets the next step's date from the sequence and pre-selects its channel; you are not asked for a date the plan already knows. A follow-up or meeting still takes an explicit time, because a person agreed to that one.
Two sequences ship, as data in outreach-cadence.mjs: a six-touch priority plan
over fourteen days across three channels, and a four-email nurture plan over six
weeks. Editing the plan is an edit to that table.
Sixty dials a day from one line. Carriers judge behaviour, not intent: volume from a single number, short calls and repeated redials are what earn a "Spam Likely" label, and a labelled number ends the channel for the whole list, not just today's calls. Every dial counts, however the call ended — a call that finished in "not interested" still put volume on the number, which is what a carrier measures. When the budget is spent the worklist stops offering phone steps and says why, including a follow-up whose saved time has arrived: it stays due, because the prospect is owed the call, but it no longer heads a list of work that can actually be done. Email and connection requests are unaffected. The day rolls over in your timezone, read from your browser and reconciled every time the workspace loads — at UTC midnight it would reset at 5pm on the west coast and hand one working afternoon two allowances. Nobody types an IANA zone name, so if you move, the page corrects it rather than asking; a zone the server cannot use leaves the working one in place instead of quietly resetting your day to UTC.
Calling hours are 8am-9pm local to the prospect's state, and a state spanning two zones is judged in both - if it is 7am anywhere in the state it is too early for the state. A prospect with no recorded state is not shown as ready to dial. The window is reported, not enforced against the log: this application does not place calls, so refusing to record one that happened would lose the touch from the budget that governs the next six.
A booked meeting is an intention; whether it happened is a separate fact. Record Met or No-show against it — and only against a meeting that was actually booked, since attendance is an outcome of something. A no-show settles the meeting that was missed and arranges its replacement, so it carries a required new time and leaves one meeting outstanding. A no-show needs a new time, because otherwise the prospect quietly falls out of the worklist. A held meeting counts as engagement and restarts the touch budget; a no-show does not, since they agreed and did not appear, so what follows is outreach again and is paced like it. When a meeting is what is next, the brief opens with the five discovery questions rather than the evidence prompts.
Pacing is only as good as the logging. A touch nobody recorded is invisible
to the limit and to the scoreboard. GET /api/lab/scoreboard, shown on the
workspace under Your funnel, reports six measurements: first-touch
service level, response rate, meetings booked per 100 prospects worked, the
share of booked meetings that were held, first conversations that led to a
second, and the number of prospects recorded as clients.
The first three measure the prospects added in the window; the meeting rates measure the meetings that happened in it, whoever they were with; the client count measures the conversions recorded in it, whenever those people were first met. The page says which under each figure, because one label reading "last 30 days" over all three would mean three different things at once.
Becoming a client ends the prospecting, and is counted rather than rated.
Record Became a client on a prospect whose record already holds a
conversation — connected, follow-up agreed, a meeting booked or held. Without one
the save is refused: the strongest figure in the report stays tied to the work
that produced it, and a client marked on an untouched record would be measured
against a funnel that skipped them. The record leaves the worklist into its own
Clients view, not the closed drawer that holds disqualified and restricted
people. Every paid provider route refuses them — the ZoomInfo candidate CSV, the
/enrichment batch export and a direct WealthFeed submission — because nobody
pays to enrich somebody they have already signed, and those are three entry
points to the same spend. Refused rather than quietly filtered: an advisor
reconciles what they submitted against what the provider charged for, and a
selection that silently shrank is what makes those two disagree. The Salesforce
export is untouched — a CRM handoff is exactly where a client belongs. It is
not
suppressed — a client is a relationship, not a contact restriction.
Every other outcome is refused on a client until the record is explicitly reopened, not only the six-touch ones. Each logged outcome sets the workflow status from itself, so any of them would move a client back out of Client and into the worklist — a touch makes them Contacted, not interested makes them Not a Fit — and most also accept a channel, which the daily dial budget counts whatever the outcome. Do not contact is the one exception, because consent is never refused on the grounds of workflow state: a client asking not to be contacted is recorded the moment they say it, without first being turned back into a prospect.
The client figure is a count with no target, and deliberately not a rate. A client who signs this month was very likely met before the window opened, so dividing by the prospects added or met inside it would place an arrival over the wrong cohort and read as a conversion rate this application cannot measure. A target would have to come from the firm's own history rather than from here. Zero clients is a true zero — none were recorded — unlike the rates above, whose empty denominators have to read as unmeasured.
Each person is counted once, dated by their first conversion, found before the window is applied rather than after. Somebody who became a client, was reopened and came back writes a second conversion, and dating the count by any matching row would report a brand-new client in a period where nobody arrived. It is the arrival being measured, so they are counted where they first arrived and not again. The log's own timestamp is that date, because the record holds no separate signing date and dating it by anything else would be a guess presented as a measurement.
A meeting is dated by the meeting, not by the note. Writing up the week on Friday would otherwise pull Tuesday's meetings into Friday's window: a meeting held six weeks ago and recorded today would appear in the last thirty days, and one held inside the window but recorded after it closed would disappear from the period it belongs to. Each recorded attendance is placed at the latest booked time that had already passed when it was logged, so the show rate and the count of meetings still awaiting an outcome are read from the same clock and cannot disagree.
Each rate names what it could not count instead of letting it improve the number. A prospect added and never touched past its deadline counts against the service level; a meeting whose time passed with neither Met nor No-show recorded is reported as awaiting outcome and counts as neither held nor missed. A rate with nothing behind it reads as unmeasured, not as zero.
Requires migration 014, which adds the channel and sequence step to logged activity, the rest-period table, and the advisor profile used to sign drafts, 015, which adds the timezone that the daily dial limit rolls over in, and 016, which records who started each contact. The client outcome needs no migration: the activity log already stores the outcome as text, so the conversion is a new value in a column that exists, and no released database has to change to deploy it.
GET /version names the rules the running service is using, not only which
build it is: cadence_version reports the pacing rules alongside
quality_version, advisor_workspace_version and contact_workspace_version.
release.sh asserts every one of them after updating the service. Without the
cadence field a release carrying new pacing rules verified identically to the
one it replaced, because every other version string on the endpoint had been
live since before pacing shipped and only the opaque release identifier moved.
A verified quality lead must meet all five reviewed criteria: age 45–73 inclusive, US residence, retained retirement assets with an eligible distribution or IRA transfer, an identified phone/email/LinkedIn contact route, and a disclosed net-worth lower bound of at least $250,000 excluding the home and net of liabilities.
Financial criteria require participant disclosure or an authorized financial document, with research consent recorded. Employer plan assets, job titles, graduation years, property values and WARN notices do not establish an individual's wealth or retirement holdings. The 0–100 score measures evidence completeness, not a probability of wealth, transfer eligibility, or investment suitability.
Traditional/contributory, rollover, and Roth IRAs support reviewed trustee-to-trustee transfers to matching tax-type destinations. Employer plans retain the existing distribution routes and in-service permission check. Unknown, stale, conflicting or suppressed records do not qualify. Age evidence uses whole attained years and accounts conservatively for possible birthdays; a 73-year-old needs current-day evidence to remain confirmed.
After installing dependencies, run pnpm demo and open the local demonstration. It uses the actual workspace and Research Lab APIs with an in-memory PostgreSQL-compatible database and clearly labeled fictional records. Contact search, lists, provider-job simulation, verification simulation, exports and Research Lab reviews work. External source calls are disabled. State resets when stopped; do not enter real personal information. Production still uses pnpm start, Firebase authentication and Cloud SQL.
The source table reports unique people first acquired during the reporting period, currently qualified people in that cohort, observed qualification yield, and reserved provider cost per qualified person. Repeated lookups and duplicate imports do not inflate acquisition counts. This cohort yield is different from the daily newly-verified count, which can include older acquisitions reviewed today. Provider-only costs are not total acquisition cost; record labor, subscriptions and infrastructure in the cost ledger.
Actual daily capacity, predictive precision, and the cheapest source are not established by this implementation or its fictional fixtures. Use the research protocol to measure them with authorized data.
Requires Node 24, pnpm 11.19.0 and Python 3 for the public plan catalog tools.
pnpm install --frozen-lockfile --ignore-scripts
pnpm build
pnpm test
python3 -m unittest discover -s test -p 'test_*.py'
Use the existing authenticated Google Cloud environment:
REFRESH_PLAN_CATALOG=1 bash release.sh
Read the release handoff for prerequisites, validation, costs, source coverage and rollback. The release verifies the new version through the custom domain. Production deployment is not implied by a successful local build or GitHub push.
pnpm verify https://prospectpilot.io review-20260101120000-1234
release.sh checks the version endpoint once, mid-deploy, and cannot be re-run
later without deploying something. This checks the same thing and more, from
outside, at any time: the release identifier and every feature version actually
being served, that the version endpoint and sign-in page are uncacheable, that an
unauthenticated visitor is sent to sign in rather than shown a workspace, that
each API answers 401 rather than data, and that a cross-origin write is
refused. It exits non-zero and names every failure.
Unauthenticated and read-only, so it is safe against production: every request is
a GET except one deliberately cross-origin POST that the origin check refuses
before reaching a handler, and no session cookie is ever sent. It therefore
cannot see the signed-in workspace — the worklist, cadence display, meeting
outcomes and dial counter still need a person with an account, and a passing run
says so rather than implying otherwise.
The external process-health route is /health, which must return 200 ok.
Cloud Run reserves some paths ending in z; /healthz is retained only as a
compatibility alias, not the external monitoring target. See Google's reserved
URL paths.
This checks that the app can respond, not database or provider availability.
Health is required by default on every host. A 404, failed request, or wrong
response body fails verification. --health-optional is an explicit exception
that reports a missing route as unchecked, never as a passing health check.
To check the service process separately from the public site:
pnpm verify https://prospectpilot.io <release-id> \
--health-base=https://<service>-<hash>-uc.a.run.app --health-required
The advisor workflow adds migration 013 for activity history and contact links, and 014 for outreach pacing, drafted touches and the advisor profile. The contact workspace requires migrations 008 and 009 before starting the service and worker; these add contacts, lists, imports, saved searches, durable tasks and cost reservations. The migration runner applies all outstanding migrations in order.
The separate Research Lab uses migration 007. It preserves observations, adds the net-worth criterion, and invalidates old qualification totals so four-gate results cannot count under the new definition. Requalification records a new first-verification timestamp under rule retirement-evidence-2. The normal migration runner applies it once.