Skip to content

Release 0.5.0: managed prospecting, Python 3.11+, max_wait= - #40

Merged
yudelevi merged 43 commits into
mainfrom
development
Oct 7, 2026
Merged

yudelevi merged 43 commits into
mainfrom
development

Conversation

@quantumdark

@quantumdark quantumdark commented Oct 7, 2026 •

Copy link
Copy Markdown
Contributor

Release 0.5.0 of discolike (SDK) and discolike-cli. Full notes in CHANGELOG.md under 0.5.0.

Breaking:

  • Python 3.10 dropped; SDK and CLI require 3.11+.
  • Polling deadline on Job.wait(), EmailJob.wait(), EmailBatch.results() renamed timeout= -> max_wait=; signup() / async_signup() take request_timeout=. Client constructor, with_options(timeout=...) and the CLI --timeout keep their names.
  • ICP-fit verdict is title case (Yes / No) on every surface.

Added:

  • Managed prospecting: client.prospecting (start, get, list, approve, update_plan, answer_intake, message, rename, cancel, delete, wait; sync and async), typed plans, checkpoints (ask/auto), seeded runs via customer_domains, saved_query_ids parts, provider spend split. CLI prospecting start/status/list/approve/message/cancel/wait.
  • Open response enums so newer API values parse.

Versions bumped in _version.py, both pyproject.toml files, the discolike[cli] extra pin and uv.lock. 910 tests pass, ruff clean.

After merge: publish a GitHub release tagged v0.5.0; publish.yml pushes both packages to PyPI on release: published. discolike-skills PR #3 (Flow 11) states SDK/CLI prospecting needs 0.5.0+.

RetriggerConfidence Score: 5/5

The PR appears safe to merge; both previous findings are fixed and no new blocking issue was found.

What we checked:

  • Incompatible arrays still get caught: _accepts() still compares item types whenever the spec permits an array. Its allowed-type check also remains unchanged.

Summary

Releases SDK and CLI 0.5.0 with managed prospecting, Python 3.11+, and renamed polling deadlines.

  • The latest changes align the pilot stopping advice across documentation.
  • The contract checker now accepts a nullable array narrowed to null, with a regression test.
  • Both previous unnumbered findings are addressed. No new actionable issues were found.

Reviews (2) · Last reviewed commit: "Fix root README pilot advice and contrac..." · Reviewed by Greptile

yudelevi and others added 30 commits September 25, 2026 10:46
Large runs now split their saved contact list into parts instead of
truncating at 50 MiB (platform commit 2fbd2d6e5). saved_query_ids
carries all of them in order, with saved_query_id staying the first
entry for backward compatibility.
A chat closed for off-topic use cancels an unapproved or paused run
with stop_reason "misuse" while an approved queued or running one
keeps working. Callers need chat_closed on the run model to know
when to stop chatting and start a new conversation. The API's 403
on a start past the daily new-chat limit already surfaces cleanly
through the existing detail-message extraction, so no client change
was needed there.
…pes in the contract script

A key with a newline passed local validation and only failed later when the
transport built the Idempotency-Key header. check_models() also compared
schema property names only, so a type or requiredness change on a mirrored
model (e.g. saved_query_ids, chat_closed) would pass silently.
The platform's GET /prospecting/runs now accepts before (a run ID) to
page past a full page of results, ordered by created_at then run_id
descending. Forward it through the SDK and CLI so callers can walk
past the 50-row max instead of only ever seeing the newest page.
Prospecting runs can now pause at decision points (a pilot check on
large lists, a search drifting off target, running short, reaching the
target) and ask the user, or decide on their own in auto mode. The API
defaults to auto so unattended callers never stall; the web chat
defaults to asking, and the CLI is a person at a terminal, so it
follows the chat rather than the API.

The brief's checkpoints field is hidden from the platform's OpenAPI
schema to keep the MCP tool listing small, so the request generator
pins it by hand and the contract check allows it instead of flagging
drift. Approval's field is pending until the platform deploys it.

At a checkpoint, `prospecting wait` asks on a terminal and keeps
waiting. Scripts and agents get a distinct exit code 7 with the
question and suggested replies on stderr, so they can answer through
`prospecting message` without parsing prose or mistaking a pause for
success.
… list id

The platform declares prospecting status, kind, role and stage as named
type aliases, which its OpenAPI spec emits as $ref schemas. The contract
check read every $ref as "object", so all four fields reported drift on
models that actually matched. It now follows the ref to the target's
type, so a genuine type change behind a ref is still caught.

Runs gain companies_saved_query_id. The spec marks it required, but the
SDK defaults it to None so it still parses servers from before the
field existed; the contract check allows that one difference instead of
failing on it.
The owner changed the rule: a poor pilot in auto mode now sharpens the
criteria once and keeps the run going with a notice, instead of
stopping outright. pilot_failed is now reserved for a re-pilot fit
still under 20% (the searches are broken); a failed sharpening attempt
falls back to the original criteria and continues.
--summary and --negate-summary help said semantic search, which the
API never did. It matches every word of a term in any order; quoting
keeps words together as one term but no longer means an exact phrase,
since the persona summary index dropped phrase positions.
A released SDK should keep working when the API adds a status, stage or
message kind, or raises a server-side cap. Response enums are now open
(Literal | str), and a run's brief parses into a response model without
the request-side limits. The contract check flags only drift that would
break parsing, and CONTRIBUTING spells out the rules for new fields.

The polling deadline is renamed timeout -> max_wait (signup takes
request_timeout) so it no longer reads like the HTTP timeout, and the
floor moves to Python 3.11 ahead of 3.10's end of life.
Customers go in as their own field so the platform can group them into
segments and find lookalikes of each; approval can narrow which segments
are expanded and turn results grouping on or off. The CLI reads the
customer list from a file, the same format as --domains-file.

The spec now carries every property that was pending in the generator
(geo filters, approve checkpoints), so those overlays are gone and the
merge path is tested with a stand-in entry instead.
The agentic prospecting default is moving from 25 companies and 2
contacts per company to 1000 and 1, matching the platform's own
fallback when a brief omits both and planning can't infer a count.
Unset fields are still dropped from the wire, so this only changes
what an unset ProspectingBrief reports locally.

_generated/requests.py is hand-edited ahead of a spec regen: the
platform OpenAPI spec still carries the old defaults, so the next
`gen_requests.py` run reproduces this once that spec change lands.

Also fixes stale doc claims from the task-17 review: the CHANGELOG's
seed_segments=None description said it keeps "every segment but
Other" when it actually keeps the run's current selection (the plan
card's default, or whatever a chat edit set) -- the approve()
docstrings already had this right.
The API now keeps reply_pending true while a "segment these" request
on a finished run is in flight, which can last more than an hour.
Callers waiting on the flag need to know the acknowledgement is not
the end, and that the flag expires after about 90 minutes if
grouping dies.
Prospecting has never shipped, so its within-release iterations,
server-only notes and a 'breaking' default change to an unreleased
model were noise; one entry describes it. The daily conversation
limit is a silent guardrail and stays out of public notes.
The API now uses DELETE on a run to remove the chat (cancelling it
first if active), so cancel() moved to POST .../cancel and delete()
wraps the new behaviour. No released version has prospecting.
The API can now retitle a prospecting chat in any status, so SDK users
get the same control the app has. Takes a generated ProspectingRunUpdate
like the other request-taking methods and returns the list() summary.
No CLI command, matching delete().

Regenerated request models from the dev spec, which also picks up the
reworded customer_domains description.
Prospecting runs: saved_query_ids and chat_closed
Managed prospecting runs now let a caller pick contact, company-check
and search engines and a credit limit on a proposed plan, and report
candidate_limit and credit_limit stop reasons. The request model is
hand-added in generated form until the deployed spec carries it.
The API now prices a run's limit at the plan's per-record rate, so the
plan settings take max_spend_usd in place of max_credits.
The API keeps the limit in run state, so run briefs never carry it;
only the plan settings take max_spend_usd.
Runs can now ask a short option card before planning. answer_intake
posts the picked values / free text per question key through the
existing messages route, so older SDKs and servers are unaffected.
ProspectingMessageRequest.text becomes optional.
yudelevi and others added 12 commits September 30, 2026 23:10
The platform added run shape and provider-spend controls to the plan
card, top-up rounds that ask before buying more companies, and two new
stop reasons. The dev spec renamed the start body to
ProspectingStartBrief, which made gen_requests drop ProspectingBrief and
ProspectingPlanSettings entirely, so the generator now maps that schema
back onto the name callers import.

Everything is additive: new request fields are optional and only sent
when set, new response fields default so older servers still parse,
and phase/deliverable/goal stay open strings. CHECKPOINT_STOP_REASONS
gains top_up because an auto run also pauses there when the next round
would pass a spending limit, and the CLI's wait loop keys off that set.

update_plan's docs now say the plan message is rewritten in place under
the same seq: a client following messages_after would never see the
re-estimated card otherwise.
…nd-intake

Prospecting run controls and guided intake
Making ProspectingMessageRequest.text optional for intake answers
dropped the local guard against an empty message. The API still
rejects a body with neither text nor intake answers (422 from its
text_or_intake validator), but the spec cannot express that rule, so
the generated model let {} and {"intake": {}} through to a wasted
request. The base request class now applies the same rule, the way
it already mirrors the platform's geo shape rules.

answer_intake shares the messages route with message(), and the
contract check kept only the first method per route, so it never
looked at answer_intake. Its signature carries a hand-written intake
key Literal and IntakeAnswer values that nothing compared to the spec.
The check now keeps every decorated method and checks answer_intake's
arguments against the body fields they fill: intake keys both ways,
IntakeAnswer fields both ways, and that the text field still exists.
If the spec stops listing allowed intake keys, the SDK's Literal would
reject keys the API accepts while the key comparison silently skipped,
since it only ran when the spec had an enum.
Close the Greptile gaps from the prospecting PR
The API now fills in 3 contacts per company when a brief gives no
count, instead of 1. The SDK model default, the CLI help and the docs
still promised 1, so a caller reading them would plan around the wrong
number of people per company.
The platform's PATCH /prospecting/runs/{run_id} now accepts an optional
checkpoints mode next to the title, so a user can stop a run from pausing
(or start asking) without restarting it. ProspectingRunUpdate is
regenerated from the spec with title optional and checkpoints added;
both are omitted from the wire when unset, so a title-only rename sends
the same body as before.
Wave runs on the platform pause at a new contacts_review checkpoint
before any email lookup, in Auto too, so CHECKPOINT_STOP_REASONS and the
CLI's wait treat it as a checkpoint. stop_reason was already an open
string, so released SDKs parse it unchanged.

The messages POST gained an optional question_seq that ties a suggested
reply to the question it was picked from; a reply to a superseded
question answers nothing. The dev spec does not carry it until the
platform deploys, so it is a PENDING_PROPERTIES entry taken from the
committed discolike_models schema, and the regenerated model omits it
from the wire when unset. The CLI's message command forwards it as
--question-seq.
The platform now takes "Find emails" at a contacts review as consent to
spend on lookups only when the reply carries question_seq; a typed one
re-posts the review. The CLI's interactive wait sent picked replies as
bare text, so it could never get past a review. A reply picked by number
now names its question, typed text still goes without it, and the
--no-input envelope gains question_seq so scripts can pass it to
`prospecting message --question-seq`.
The platform now starts email lookups for contacts already in
DiscoLike's database while a wave researches, with plan approval as the
consent, so the contacts_review no longer comes before every lookup. The
READMEs said it did. The plan message's data gains email_lookup_note;
message data is a plain dict, so the SDK reads it without a change.
With DiscoLike Groove most of a run's provider spend is the customer's
own search provider, so the API now reports each provider's part beside
the total. The fields default to None so the SDK still parses servers
and runs from before the split.
Breaking: Python 3.11+, and the polling deadline on Job.wait(),
EmailJob.wait() and EmailBatch.results() is max_wait= (signup takes
request_timeout=). Adds managed prospecting to the SDK and CLI.
Comment thread README.md Outdated
Comment thread scripts/check_contract.py Outdated
The root README still said an auto run stops after one failed re-pilot,
contradicting the SDK README, CLI help and field description: it only
stops when the re-pilot fit is under 20%.

The contract check compared array item types even when the spec field
cannot be an array, so narrowing an optional array to null was flagged
as incompatible although the SDK reads it fine.
@yudelevi
yudelevi merged commit 995b673 into main Oct 7, 2026
16 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants