author-listing5.36 KB
View saved version →
---
name: author-listing
description: Create, update, and publish a commercial real estate listing on SPACEXPLORATION from a flyer, offering memorandum, or details the user provides. Use when a broker or owner wants to list a property for sale or lease, turn a flyer or OM into a listing, add photos, edit or publish a listing they own, check publish progress, or take a listing off the market. Requires a SPACEXPLORATION account.
---
# Author a listing on SPACEXPLORATION
The user's explicit instructions take precedence over this skill. When the user has already asked for a specific action, such as publishing or withdrawing a specific listing, carry it out without asking again.
Authoring tools act on the user's own account. The first one to run asks the user to sign in through the browser. The account also needs:
- **A verified email address and a completed onboarding** to create or edit listings.
- **A verified phone number** to publish.
When a tool reports one of these as missing, pass the message on, including the link it contains, and stop. These checks are completed on spacexploration.com, not through tools.
Asked what listing costs, how long a listing stays up, or another question about SPACEXPLORATION itself? Call `get_faq`, answer from it, and link the entry's `url`.
## Honesty comes first
A listing is a public, broker-attributed record. **Enter only what the user or their document states.** Leave a field empty when the source is silent; don't estimate, round, or infer. When publishing, SPACEXPLORATION fills computed facts such as flood zone, demographics, public records, and market data from authoritative sources. A guessed value in a broker-stated field is worse than a blank. When something is ambiguous, such as price per square foot versus a total price, ask.
## Flow
Every step after creation uses the listing's `hashid`.
1. **`geocode_address`** turns the property's address into the coordinates, county, and `place_id` that `create_listing` requires. Use its output as-is; don't geocode some other way.
2. **`create_listing`** takes the geocoded fields plus `property_type` (a value from the `get_registry` property_type attribute) and `listing_type` (`sale` or `lease`). Include `apn` when the document gives a parcel number. Pass an `idempotency_key` (a UUID) so a retry can't create a duplicate. It returns a draft with its `hashid`.
3. **`update_listing`** sets the core groups. Send each group whole, not just the field that changed:
- `pricing`: `sale_price` for a sale. For a lease, `lease_rate_period` is the basis every rate is quoted in, such as `per_sqft_year`. Set `price_on_request: true` when no price is published.
- `spaces` (leases only): a lease is priced per suite. Publishing needs at least one available suite with its `available_sqft` and a `lease_rate` or `price_on_request: true`. Send the whole list, because a suite left out is removed. To change suites, start from the `spaces` that `get_listing` returns and keep each suite's `id`. A whole building leased as one is a single suite; for it, you can set `lease_rate` and `available_sqft` in `pricing` instead of sending `spaces`.
- `marketing`: `headline`, `summary`, `highlights` (an array of short strings). Draw these from the source's own wording.
- `parcel`: `lot_size` is **integer square feet**. Convert acres × 43,560 and set `lot_size_unit` to the unit the source used.
4. **`set_listing_attributes`** sets the detailed fields: a map from registry `field` to value, e.g. `{"attr_industrial_clear_height": 32, "attr_industrial_dock_doors": 4}`. Only fields `get_registry` marks `"writable": true` are accepted. Send `null` to clear a field.
5. **Photos.** `attach_listing_photo` takes one public `https` image URL per call. The server fetches the image and runs content moderation on it. A photo whose `moderation_status` is `rejected` or `escalated` stays hidden and blocks publishing until it is removed with `delete_attachment` or replaced. For a local file, `sign_attachment_upload` returns a presigned URL to `PUT` the bytes to, then `confirm_attachment_upload` finalizes it. This path only works where you can make HTTP requests yourself, such as a coding agent with shell access.
6. **Review with the user.** Call `get_listing`, summarize what will go public, and get explicit approval before publishing.
7. **`publish_listing`** starts an asynchronous pipeline that enriches the listing and then makes it public. If the listing isn't ready, the tool returns a checklist of what is missing; resolve those items and try again. When it starts, it also returns `suggestions`: fixes that don't block publishing but improve the listing, such as a flyer used as the cover photo, a placeholder address, or an unusual cap rate. Pass each one on to the user, and offer to make the fix once the listing is live.
8. **`get_publish_status`** with the `hashid` reports progress. Poll it until `state` is `completed` or `failed`. On `failed`, report the reason it gives. Once published, `get_listing` returns the listing's public `url`; give it to the user.
## Manage existing listings
- `list_my_listings` returns the user's listings, optionally filtered by `status` (`draft`, `active`, `sold`, `leased`, `withdrawn`, …).
- `withdraw_listing` removes a listing from public search **permanently**: a withdrawn listing can't be reactivated, and relisting means creating a new listing. Explain this and get the user's confirmation before calling it.
saved-searches2.52 KB
View saved version →
---
name: saved-searches
description: Set up and manage SPACEXPLORATION saved searches that email the user when new commercial listings match. Use when the user wants to be alerted, notified, or kept posted about new commercial property that fits their criteria, or wants to review or remove their existing alerts. Requires signing in to SPACEXPLORATION.
---
# Saved searches on SPACEXPLORATION
The user's explicit instructions take precedence over this skill. When the user has already asked for a specific action, such as deleting a specific saved search, carry it out without asking again.
A saved search stores a set of filters on the user's SPACEXPLORATION account. When new listings that match are published, SPACEXPLORATION emails the user a daily digest. The user can also manage their saved searches on the web at https://spacexploration.com/my/saved-searches.
These tools need the user's account. The first time one runs, the user is asked to sign in to SPACEXPLORATION in the browser. If they decline, say that alerts need an account and offer to keep searching without one.
## Create one
1. **Agree on the criteria first.** Run the search with the `search-listings` skill and show the user what currently matches, so they confirm the filters are right before anything is saved.
2. **Check for duplicates.** Call `list_my_saved_searches`. If a saved search already covers the same criteria, tell the user. There is no update tool, so changing one means deleting the old search and saving a new one, and only with the user's go-ahead.
3. **Encode the location as filters.** `save_search` stores only `query` and `filters`, not map `bounds`. A search that relied on `bounds` for "near Denver" has to be saved with `city` or `county` filters instead, such as `"city": ["Denver", "Aurora", "Lakewood"]`. Tell the user which places the alert covers.
4. **Save it.** Call `save_search` with a short descriptive `name`, the `filters`, and `query` if the search used free text:
```json
{
"name": "Denver-area industrial under $5M",
"filters": {
"property_type": ["industrial"],
"listing_type": ["sale"],
"price": { "max": 5000000 },
"city": ["Denver", "Aurora", "Commerce City"]
}
}
```
Confirm what you saved and that alerts go to the email address on their account.
## Review and remove
- `list_my_saved_searches` returns each saved search with its numeric `id`, filters, and alert schedule.
- `delete_saved_search` takes that `id`. Deleting can't be undone, so name the search you're about to delete and get the user's confirmation first.
search-listings5.84 KB
View saved version →
---
name: search-listings
description: Find and compare commercial real estate on SPACEXPLORATION — industrial, office, retail, multifamily, and land, for sale or lease, anywhere in the US. Use when the user wants to search for commercial property, filter by price, size, cap rate, location, or building features, look up a specific listing, compare listings side by side, or check the public data on any US building by its address (flood zone, hazard risk, EPA records, demographics, county record), listed or not. Searching needs no account; a building lookup asks the user to sign in to SPACEXPLORATION in the browser.
---
# Search SPACEXPLORATION listings
The user's explicit instructions take precedence over this skill.
SPACEXPLORATION is an MLS for commercial property. Every read tool works without signing in, except looking up a building by address: the first time it runs, the user is asked to sign in to SPACEXPLORATION in the browser.
## Choose a starting point
- **The user asks in plain language** ("warehouses near Denver under $5M with dock doors"): call `interpret_search` with their sentence as `prompt`. Pass the `filters` it returns to `search_listings`. If it also returns `bounds`, pass those as well. Bounds hold the "near <place>" part, and without them the search covers the whole country.
- **You need precise or repeated control:** call `get_registry` once and build `filters` yourself. Anonymous callers can make about 6 `interpret_search` calls per minute, so do this for follow-up refinements too.
## Build filters from the registry
`get_registry` returns `attributes` and `sort_options`. Each attribute's `field` is the only valid filter key. Shape each value by the attribute's `filter`:
| `filter` | Filter value |
| --- | --- |
| `range` | `{"min": …, "max": …}`. Either bound is optional. Dates take ISO dates, e.g. `{"min": "2027-01-01"}` |
| `any_of` | array of the attribute's `values`, e.g. `["industrial", "office"]`. Where `values` are `{value, label}` pairs, send the `value` |
| `boolean` | `true` or `false` |
| `equals` | a single exact value |
- `applies_to` and `applies_to_listing_type` say which property and listing types a field is meaningful for. For example, cap rate applies to sale listings and lease structure to lease listings. Filtering on a field that doesn't apply silently excludes every other type.
- Location: `state` takes two-letter codes (`["CO"]`), and `city` and `county` take exact names. Use them when the user names a place and you have no `bounds`; without a location filter or `bounds` the search covers the whole country.
- `sort` must be one of `sort_options`, e.g. `price:asc`, `attr_cap_rate:desc`, or `views_30d:desc` for popular listings.
- `query` is free text matched against address, city, and keywords. Use it for a street address or a term that isn't a registry field.
```json
{
"filters": {
"property_type": ["industrial"],
"listing_type": ["sale"],
"price": { "max": 5000000 },
"attr_industrial_dock_doors": { "min": 1 }
},
"bounds": { "sw_lat": 39.4, "sw_lng": -105.3, "ne_lat": 40.1, "ne_lng": -104.6 },
"sort": "price:asc"
}
```
## Read results
`search_listings` returns `hits`, `facets` (counts per value, useful for suggesting refinements), `found`, `page`, and `last_page`. Pass `page` to page through results; there are 24 hits per page.
Each hit carries a `hashid`, the listing page `url`, and two timestamps: `listed_at` (when it went live) and `updated_at` (when it last changed). Call `get_listing` with the `hashid` for the full record: pricing, every populated attribute with its label and unit, parcel and public-record data, photos, and documents. Broker contact details appear only when the caller is allowed to see them.
Link the user to a listing with its `url`. Don't build the link yourself.
## Look up a building by address
When the user asks about a specific building, on the market or not ("is 910 Elysian Fields Ave in a flood zone?", "what do we know about this property?"), call `look_up_parcel` with its full street address, street number included. The first time it runs, the user is asked to sign in to SPACEXPLORATION in the browser. A road, a town, or a partial address is refused, so ask for the street number.
It returns the building page `url` to share, `details` keyed by registry path (FEMA flood zone, natural hazard risk, EPA records nearby, Census demographics, access and amenities), `public_record` (the county's owner, values, taxes, tax lots, and recorded sales, each figure with a numbered source) where research has found it, and any live `listings` in it (pass a `hashid` to `get_listing`).
A building looked up for the first time fills in over a minute or more. While `status.gathering` or `status.researching_county_record` is true, follow `status.note`: check on it with `get_parcel` and the returned `parcel.hashid` instead of repeating the lookup. `get_parcel` starts nothing and works without signing in.
## Answer questions about SPACEXPLORATION
Asked how SPACEXPLORATION works, what it covers, or another question about the service itself rather than a property? Call `get_faq`, answer from it, and link the entry's `url`.
## Report honestly
- Say how many listings matched (`found`), and when a search came back empty, say which filter was most restrictive.
- When recency matters, say when a listing was listed or last updated.
- Present only values the tools returned. A missing attribute means the listing doesn't state it. Don't fill it in.
- For a building, `public_record` cites its sources by number: name the county source when you quote a figure, and say a field is unknown when it is missing rather than estimating it.
- Some attributes are computed from public sources: flood zone, census demographics, walk and transit scores, proximity, market medians, and `attr_record_*` assessor data. When those matter to the decision, say they come from public data, not from the broker.