Repository: bytecodealliance/wasmtime
Pull request #6390 (2023-05-16 21:23:05)

Update Wasmtime for upcoming WIT changes
This PR integrates bytecodealliance/wasm-tools#1027 into Wasmtime. The main changes here are:

* WIT syntax is updated with WebAssembly/component-model#193
* Generated bindings in the `bindgen!` macro have been updated to reflect the new structure of WIT.
* The accepted component model binary format has been updated to account for changes.

This PR disables wasi-http tests and the on-by-default feature because the WIT syntax has been updated but the submodule containing the WITs has not been updated yet so there's no way to get that building temporarily. Once that's updated then this can be reenabled.

<!--
Please make sure you include the following information:

- If this work has been discussed elsewhere, please include a link to that
  conversation. If it was discussed in an issue, just mention "issue #...".

- Explain why this change is needed. If the details are in an issue already,
  this can be brief.

Our development process is documented in the Wasmtime book:
https://docs.wasmtime.dev/contributing-development-process.html

Please ensure all communication follows the code of conduct:
https://github.com/bytecodealliance/wasmtime/blob/main/CODE_OF_CONDUCT.md
-->


alexcrichton: I'll note that I'm opening this as a draft as I'm working my way up the stack. My goal is to prove out https://github.com/bytecodealliance/wasm-tools/pull/1027 and once everything is ready have a day I spend landing the various changes.
alexcrichton: Ok I've now updated this for the final set of merged changes to wasm-tools, which aren't yet published. The major changes in this PR are now:

* All wasm-tools deps are updated (currently sitting at git deps to my "bump" branch)
* WIT syntax is changing, as well as the binary format of components
* All WIT files vendored in this repository are updated to the new syntax. Notably the wasi-http WITs are not updated because they're a submodule. This means that all wasi-http-related tests and support are disabled.
* There is now only one copy of WIT for WASI, and all other duplicate copies are deleted.
* All of the preview2 implementation has been updated for the new hierarchy of modules created by `wasmtime::component::bindgen!`

One interesting aspect of this is that there's a temporary git dependency on wit-bindgen. I'm not actually sure how to get rid of that because the adapter requires wit-bindgen and it's not easy to remove that. This is somewhat ok though since we don't publish anything with wit-bindgen so I'm hoping it's ok to have a temporary state of affairs with a git dep here before I can go use this PR to update wit-bindgen to make a release there.
alexcrichton: cc @rvolosatovs and @sunfishcode as y'all are likely interested in the various changes here too

Patch:
diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml
index 4b0fa85ab..8de9ac36e 100644
--- a/.github/workflows/main.yml
+++ b/.github/workflows/main.yml
@@ -222,6 +222,7 @@ jobs:
         cargo doc --no-deps --workspace \
           --exclude wasmtime-cli \
           --exclude test-programs \
+          --exclude wasi-http-tests \
           --exclude cranelift-codegen-meta \
           --features component-model
     - run: cargo doc --package cranelift-codegen-meta --document-private-items
diff --git a/Cargo.lock b/Cargo.lock
index 4ebf1c432..1121cd24e 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -686,7 +686,7 @@ dependencies = [
  "target-lexicon",
  "thiserror",
  "toml",
- "wasmparser 0.105.0",
+ "wasmparser 0.107.0",
  "wat",
 ]
 
@@ -862,7 +862,7 @@ dependencies = [
  "serde",
  "smallvec",
  "target-lexicon",
- "wasmparser 0.105.0",
+ "wasmparser 0.107.0",
  "wasmtime-types",
  "wat",
 ]
@@ -3150,7 +3150,7 @@ dependencies = [
  "wasmtime",
  "wasmtime-wasi",
  "wasmtime-wasi-http",
- "wit-component 0.9.0",
+ "wit-component",
 ]
 
 [[package]]
@@ -3675,74 +3675,52 @@ dependencies = [
 
 [[package]]
 name = "wasm-encoder"
-version = "0.26.0"
+version = "0.29.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d05d0b6fcd0aeb98adf16e7975331b3c17222aa815148f5b976370ce589d80ef"
+checksum = "18c41dbd92eaebf3612a39be316540b8377c871cb9bde6b064af962984912881"
 dependencies = [
  "leb128",
 ]
 
-[[package]]
-name = "wasm-encoder"
-version = "0.27.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e77053dc709db790691d3732cfc458adc5acc881dec524965c608effdcd9c581"
-dependencies = [
- "leb128",
-]
-
-[[package]]
-name = "wasm-metadata"
-version = "0.5.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dbdef99fafff010c57fabb7bc703f0903ec16fcee49207a22dcc4f78ea44562f"
-dependencies = [
- "anyhow",
- "indexmap",
- "serde",
- "wasm-encoder 0.26.0",
- "wasmparser 0.104.0",
-]
-
 [[package]]
 name = "wasm-metadata"
-version = "0.6.0"
+version = "0.8.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "27e6532071b112df81d756fabafab8cc882b84ae3d6ce9b90f3d90c80e4abe05"
+checksum = "36e5156581ff4a302405c44ca7c85347563ca431d15f1a773f12c9c7b9a6cdc9"
 dependencies = [
  "anyhow",
  "indexmap",
  "serde",
- "wasm-encoder 0.27.0",
- "wasmparser 0.105.0",
+ "wasm-encoder 0.29.0",
+ "wasmparser 0.107.0",
 ]
 
 [[package]]
 name = "wasm-mutate"
-version = "0.2.25"
+version = "0.2.27"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7b8c74fd20d97b9ba8b1a6e3ccc6ec715e6c6d4605668926e582e88580180d96"
+checksum = "f354beb7e2ccaf66dd263328486240899755ae0df3ac4b76305dace67fbd2169"
 dependencies = [
  "egg",
  "log",
  "rand 0.8.5",
  "thiserror",
- "wasm-encoder 0.27.0",
- "wasmparser 0.105.0",
+ "wasm-encoder 0.29.0",
+ "wasmparser 0.107.0",
 ]
 
 [[package]]
 name = "wasm-smith"
-version = "0.12.8"
+version = "0.12.10"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "13c11c745f6f4ff2f953d8a94ef056b04b468fc021285cfaf614e77791c05499"
+checksum = "027ec1c470cd5d56c43b8e02040250b136ddb5975dd76a1c16915137f5f17e76"
 dependencies = [
  "arbitrary",
  "flagset",
  "indexmap",
  "leb128",
- "wasm-encoder 0.27.0",
- "wasmparser 0.105.0",
+ "wasm-encoder 0.29.0",
+ "wasmparser 0.107.0",
 ]
 
 [[package]]
@@ -3794,22 +3772,12 @@ dependencies = [
 
 [[package]]
 name = "wasmparser"
-version = "0.104.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6a396af81a7c56ad976131d6a35e4b693b78a1ea0357843bd436b4577e254a7d"
-dependencies = [
- "indexmap",
- "url",
-]
-
-[[package]]
-name = "wasmparser"
-version = "0.105.0"
+version = "0.107.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "83be9e0b3f9570dc1979a33ae7b89d032c73211564232b99976553e5c155ec32"
+checksum = "29e3ac9b780c7dda0cac7a52a5d6d2d6707cc6e3451c9db209b6c758f40d7acb"
 dependencies = [
  "indexmap",
- "url",
+ "semver",
 ]
 
 [[package]]
@@ -3823,12 +3791,12 @@ dependencies = [
 
 [[package]]
 name = "wasmprinter"
-version = "0.2.57"
+version = "0.2.59"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "50b0e5ed7a74a065637f0d7798ce5f29cadb064980d24b0c82af5200122fa0d8"
+checksum = "cc960b30b84abca377768f3c62cff3a1c74db8c0f6759ed581827da0bd3a3fed"
 dependencies = [
  "anyhow",
- "wasmparser 0.105.0",
+ "wasmparser 0.107.0",
 ]
 
 [[package]]
@@ -3855,7 +3823,7 @@ dependencies = [
  "target-lexicon",
  "tempfile",
  "wasi-cap-std-sync",
- "wasmparser 0.105.0",
+ "wasmparser 0.107.0",
  "wasmtime-cache",
  "wasmtime-component-macro",
  "wasmtime-component-util",
@@ -3970,8 +3938,8 @@ dependencies = [
  "test-programs",
  "tokio",
  "walkdir",
- "wasm-encoder 0.27.0",
- "wasmparser 0.105.0",
+ "wasm-encoder 0.29.0",
+ "wasmparser 0.107.0",
  "wasmtime",
  "wasmtime-cache",
  "wasmtime-cli-flags",
@@ -3986,7 +3954,7 @@ dependencies = [
  "wasmtime-wasi-nn",
  "wasmtime-wasi-threads",
  "wasmtime-wast",
- "wast 58.0.0",
+ "wast 60.0.0",
  "wat",
  "windows-sys 0.48.0",
 ]
@@ -4039,7 +4007,7 @@ dependencies = [
  "object",
  "target-lexicon",
  "thiserror",
- "wasmparser 0.105.0",
+ "wasmparser 0.107.0",
  "wasmtime-cranelift-shared",
  "wasmtime-environ",
 ]
@@ -4074,8 +4042,8 @@ dependencies = [
  "serde",
  "target-lexicon",
  "thiserror",
- "wasm-encoder 0.27.0",
- "wasmparser 0.105.0",
+ "wasm-encoder 0.29.0",
+ "wasmparser 0.107.0",
  "wasmprinter",
  "wasmtime-component-util",
  "wasmtime-types",
@@ -4090,7 +4058,7 @@ dependencies = [
  "component-fuzz-util",
  "env_logger 0.10.0",
  "libfuzzer-sys",
- "wasmparser 0.105.0",
+ "wasmparser 0.107.0",
  "wasmprinter",
  "wasmtime-environ",
  "wat",
@@ -4144,7 +4112,7 @@ dependencies = [
  "rand 0.8.5",
  "smallvec",
  "target-lexicon",
- "wasmparser 0.105.0",
+ "wasmparser 0.107.0",
  "wasmtime",
  "wasmtime-fuzzing",
 ]
@@ -4164,12 +4132,12 @@ dependencies = [
  "target-lexicon",
  "tempfile",
  "v8",
- "wasm-encoder 0.27.0",
+ "wasm-encoder 0.29.0",
  "wasm-mutate",
  "wasm-smith",
  "wasm-spec-interpreter",
  "wasmi",
- "wasmparser 0.105.0",
+ "wasmparser 0.107.0",
  "wasmprinter",
  "wasmtime",
  "wasmtime-wast",
@@ -4251,7 +4219,7 @@ dependencies = [
  "cranelift-entity",
  "serde",
  "thiserror",
- "wasmparser 0.105.0",
+ "wasmparser 0.107.0",
 ]
 
 [[package]]
@@ -4338,7 +4306,7 @@ dependencies = [
  "anyhow",
  "log",
  "wasmtime",
- "wast 58.0.0",
+ "wast 60.0.0",
 ]
 
 [[package]]
@@ -4350,7 +4318,7 @@ dependencies = [
  "gimli",
  "object",
  "target-lexicon",
- "wasmparser 0.105.0",
+ "wasmparser 0.107.0",
  "wasmtime-cranelift-shared",
  "wasmtime-environ",
  "winch-codegen",
@@ -4376,23 +4344,23 @@ dependencies = [
 
 [[package]]
 name = "wast"
-version = "58.0.0"
+version = "60.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "372eecae2d10a5091c2005b32377d7ecd6feecdf2c05838056d02d8b4f07c429"
+checksum = "bd06cc744b536e30387e72a48fdd492105b9c938bb4f415c39c616a7a0a697ad"
 dependencies = [
  "leb128",
  "memchr",
  "unicode-width",
- "wasm-encoder 0.27.0",
+ "wasm-encoder 0.29.0",
 ]
 
 [[package]]
 name = "wat"
-version = "1.0.64"
+version = "1.0.66"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6d47446190e112ab1579ab40b3ad7e319d859d74e5134683f04e9f0747bf4173"
+checksum = "5abe520f0ab205366e9ac7d3e6b2fc71de44e32a2b58f2ec871b6b575bdcea3b"
 dependencies = [
- "wast 58.0.0",
+ "wast 60.0.0",
 ]
 
 [[package]]
@@ -4520,7 +4488,7 @@ dependencies = [
  "regalloc2",
  "smallvec",
  "target-lexicon",
- "wasmparser 0.105.0",
+ "wasmparser 0.107.0",
  "wasmtime-environ",
 ]
 
@@ -4564,7 +4532,7 @@ dependencies = [
  "similar",
  "target-lexicon",
  "toml",
- "wasmparser 0.105.0",
+ "wasmparser 0.107.0",
  "wasmtime-environ",
  "wat",
  "winch-codegen",
@@ -4717,9 +4685,8 @@ dependencies = [
 
 [[package]]
 name = "wit-bindgen"
-version = "0.6.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ad22d93d3f55847ac4b3df31607a26f35231754ef472382319de032770d8b5bf"
+version = "0.7.0"
+source = "git+https://github.com/bytecodealliance/wit-bindgen?branch=wasmtime-2023-05-26-wit-changes#7df2c15f54d7c20593ff2d38db48014889c9a46d"
 dependencies = [
  "bitflags 2.2.1",
  "wit-bindgen-rust-macro",
@@ -4727,33 +4694,30 @@ dependencies = [
 
 [[package]]
 name = "wit-bindgen-core"
-version = "0.6.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5bc1b5a6e87f16491f2297f75312dc0fb354f8c88c8bece53ea0d3167fc98867"
+version = "0.7.0"
+source = "git+https://github.com/bytecodealliance/wit-bindgen?branch=wasmtime-2023-05-26-wit-changes#7df2c15f54d7c20593ff2d38db48014889c9a46d"
 dependencies = [
  "anyhow",
- "wit-component 0.8.2",
+ "wit-component",
  "wit-parser",
 ]
 
 [[package]]
 name = "wit-bindgen-rust"
-version = "0.6.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7946a66f1132d3322c29de9d28097bd263f67e1e0909054f91253aa103cdf8be"
+version = "0.7.0"
+source = "git+https://github.com/bytecodealliance/wit-bindgen?branch=wasmtime-2023-05-26-wit-changes#7df2c15f54d7c20593ff2d38db48014889c9a46d"
 dependencies = [
  "heck",
- "wasm-metadata 0.5.0",
+ "wasm-metadata",
  "wit-bindgen-core",
  "wit-bindgen-rust-lib",
- "wit-component 0.8.2",
+ "wit-component",
 ]
 
 [[package]]
 name = "wit-bindgen-rust-lib"
-version = "0.6.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0baf7325748c5d363ab6ed3ddbd155c241cfe385410c61f2505ec978a61a2d2c"
+version = "0.7.0"
+source = "git+https://github.com/bytecodealliance/wit-bindgen?branch=wasmtime-2023-05-26-wit-changes#7df2c15f54d7c20593ff2d38db48014889c9a46d"
 dependencies = [
  "heck",
  "wit-bindgen-core",
@@ -4761,63 +4725,45 @@ dependencies = [
 
 [[package]]
 name = "wit-bindgen-rust-macro"
-version = "0.6.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "42c131da5d2ba7746908e1401d474640371c31ad05281528c2a9e945a87d19be"
+version = "0.7.0"
+source = "git+https://github.com/bytecodealliance/wit-bindgen?branch=wasmtime-2023-05-26-wit-changes#7df2c15f54d7c20593ff2d38db48014889c9a46d"
 dependencies = [
  "anyhow",
  "proc-macro2",
  "syn 2.0.16",
  "wit-bindgen-core",
  "wit-bindgen-rust",
- "wit-component 0.8.2",
-]
-
-[[package]]
-name = "wit-component"
-version = "0.8.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e291ff83cb9c8e59963cc6922bdda77ed8f5517d6835f0c98070c4e7f1ae4996"
-dependencies = [
- "anyhow",
- "bitflags 1.3.2",
- "indexmap",
- "log",
- "url",
- "wasm-encoder 0.26.0",
- "wasm-metadata 0.5.0",
- "wasmparser 0.104.0",
- "wit-parser",
+ "wit-component",
 ]
 
 [[package]]
 name = "wit-component"
-version = "0.9.0"
+version = "0.11.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b3cc435c15009f80d5e114d0dd3792959171f1fc28be2418e0f570d83b925a33"
+checksum = "7cbd4c7f8f400327c482c88571f373844b7889e61460650d650fc5881bb3575c"
 dependencies = [
  "anyhow",
  "bitflags 1.3.2",
  "indexmap",
  "log",
- "url",
- "wasm-encoder 0.27.0",
- "wasm-metadata 0.6.0",
- "wasmparser 0.105.0",
+ "wasm-encoder 0.29.0",
+ "wasm-metadata",
+ "wasmparser 0.107.0",
  "wit-parser",
 ]
 
 [[package]]
 name = "wit-parser"
-version = "0.7.1"
+version = "0.8.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5ca2581061573ef6d1754983d7a9b3ed5871ef859d52708ea9a0f5af32919172"
+checksum = "6daec9f093dbaea0e94043eeb92ece327bbbe70c86b1f41aca9bbfefd7f050f0"
 dependencies = [
  "anyhow",
  "id-arena",
  "indexmap",
  "log",
  "pulldown-cmark",
+ "semver",
  "unicode-xid",
  "url",
 ]
diff --git a/Cargo.toml b/Cargo.toml
index 201494b69..6c33b266f 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -197,18 +197,18 @@ io-lifetimes = { version = "1.0.0", default-features = false }
 rustix = "0.37.13"
 
 # wit-bindgen:
-wit-bindgen = "0.6.0"
+wit-bindgen = { version = "0.7.0", default-features = false }
 
 # wasm-tools family:
-wasmparser = "0.105.0"
-wat = "1.0.64"
-wast = "58.0.0"
-wasmprinter = "0.2.57"
-wasm-encoder = "0.27.0"
-wasm-smith = "0.12.8"
-wasm-mutate = "0.2.25"
-wit-parser = "0.7.1"
-wit-component = "0.9.0"
+wasmparser = "0.107.0"
+wat = "1.0.66"
+wast = "60.0.0"
+wasmprinter = "0.2.59"
+wasm-encoder = "0.29.0"
+wasm-smith = "0.12.10"
+wasm-mutate = "0.2.27"
+wit-parser = "0.8.0"
+wit-component = "0.11.0"
 
 # Non-Bytecode Alliance maintained dependencies:
 # --------------------------
@@ -248,7 +248,8 @@ default = [
   "vtune",
   "wasi-nn",
   "wasi-threads",
-  "wasi-http",
+  # TODO: the WIT needs to be updated
+  #"wasi-http",
   "pooling-allocator",
 ]
 jitdump = ["wasmtime/jitdump"]
@@ -311,3 +312,5 @@ debug-assertions = false
 # string initializers.
 overflow-checks = false
 
+[patch.crates-io]
+wit-bindgen = { git = 'https://github.com/bytecodealliance/wit-bindgen', branch = 'wasmtime-2023-05-26-wit-changes' }
diff --git a/cranelift/wasm/src/sections_translator.rs b/cranelift/wasm/src/sections_translator.rs
index 68705ad4a..e7b0486ea 100644
--- a/cranelift/wasm/src/sections_translator.rs
+++ b/cranelift/wasm/src/sections_translator.rs
@@ -56,6 +56,9 @@ pub fn parse_type_section<'a>(
                 let ty = environ.convert_func_type(&wasm_func_ty);
                 environ.declare_type_func(ty)?;
             }
+            Type::Array(_) => {
+                unimplemented!("gc proposal");
+            }
         }
     }
     Ok(())
diff --git a/crates/component-macro/src/bindgen.rs b/crates/component-macro/src/bindgen.rs
index 028659204..e41e0fa2a 100644
--- a/crates/component-macro/src/bindgen.rs
+++ b/crates/component-macro/src/bindgen.rs
@@ -78,7 +78,16 @@ impl Parse for Config {
                         if inline.is_some() {
                             return Err(Error::new(s.span(), "cannot specify a second source"));
                         }
-                        inline = Some(format!("default world interfaces {{ {} }}", s.value()));
+                        inline = Some(format!(
+                            "
+                                package wasmtime:component-macro-synthesized
+
+                                world interfaces {{
+                                    {}
+                                }}
+                            ",
+                            s.value()
+                        ));
 
                         if world.is_some() {
                             return Err(Error::new(
@@ -86,7 +95,7 @@ impl Parse for Config {
                                 "cannot specify a world with `interfaces`",
                             ));
                         }
-                        world = Some("macro-input.interfaces".to_string());
+                        world = Some("interfaces".to_string());
 
                         opts.only_interfaces = true;
                     }
@@ -130,7 +139,7 @@ fn parse_source(
         } else {
             let pkg = UnresolvedPackage::parse_file(path)?;
             files.extend(pkg.source_files().map(|s| s.to_owned()));
-            resolve.push(pkg, &Default::default())
+            resolve.push(pkg)
         }
     };
 
@@ -141,16 +150,7 @@ fn parse_source(
     };
 
     let inline_pkg = if let Some(inline) = inline {
-        let deps = resolve
-            .packages
-            .iter()
-            .map(|(id, p)| (p.name.clone(), id))
-            .collect();
-
-        Some(resolve.push(
-            UnresolvedPackage::parse("macro-input".as_ref(), &inline)?,
-            &deps,
-        )?)
+        Some(resolve.push(UnresolvedPackage::parse("macro-input".as_ref(), &inline)?)?)
     } else {
         None
     };
diff --git a/crates/environ/src/component/translate.rs b/crates/environ/src/component/translate.rs
index 5abd9e777..cb2306e25 100644
--- a/crates/environ/src/component/translate.rs
+++ b/crates/environ/src/component/translate.rs
@@ -8,7 +8,7 @@ use anyhow::{bail, Result};
 use indexmap::IndexMap;
 use std::collections::HashMap;
 use std::mem;
-use wasmparser::{Chunk, Encoding, Parser, Payload, Validator};
+use wasmparser::{Chunk, ComponentExternName, Encoding, Parser, Payload, Validator};
 
 mod adapt;
 pub use self::adapt::*;
@@ -164,7 +164,7 @@ struct Translation<'data> {
 #[allow(missing_docs)]
 enum LocalInitializer<'data> {
     // imports
-    Import(&'data str, TypeDef),
+    Import(ComponentExternName<'data>, TypeDef),
 
     // canonical function sections
     Lower(ComponentFuncIndex, LocalCanonicalOptions),
@@ -622,7 +622,7 @@ impl<'a, 'data> Translator<'a, 'data> {
                 for export in s {
                     let export = export?;
                     let item = self.kind_to_item(export.kind, export.index);
-                    let prev = self.result.exports.insert(export.name, item);
+                    let prev = self.result.exports.insert(export.name.as_str(), item);
                     assert!(prev.is_none());
                     self.result
                         .initializers
@@ -831,9 +831,9 @@ impl<'a, 'data> Translator<'a, 'data> {
                 ComponentItem::Type(ty) => Some(ComponentItemType::Type(ty)),
                 ComponentItem::Module(_) => None,
             };
-            map.insert(export.name, idx);
+            map.insert(export.name.as_str(), idx);
             if let Some(ty) = ty {
-                types.insert(export.name, ty);
+                types.insert(export.name.as_str(), ty);
             }
         }
 
@@ -900,15 +900,15 @@ impl<'a, 'data> Translator<'a, 'data> {
             // An imported component instance is being aliased, so the type of
             // the aliased item is directly available from the instance type.
             ComponentInstanceType::Index(ty) => {
-                let (_url, ty) = &self.types[ty].exports[name];
-                self.push_typedef(*ty);
+                let ty = self.types[ty].exports[name];
+                self.push_typedef(ty);
             }
 
             // An imported component was instantiated so the type of the aliased
             // export is available through the type of the export on the
             // original component.
             ComponentInstanceType::InstantiatedIndex(ty) => {
-                let (_, ty) = self.types[ty].exports[name];
+                let ty = self.types[ty].exports[name];
                 self.push_typedef(ty);
             }
 
diff --git a/crates/environ/src/component/translate/inline.rs b/crates/environ/src/component/translate/inline.rs
index 95aa449c1..62a7d007a 100644
--- a/crates/environ/src/component/translate/inline.rs
+++ b/crates/environ/src/component/translate/inline.rs
@@ -82,9 +82,12 @@ pub(super) fn run(
             LocalInitializer::Import(name, ty) => (name, ty),
             _ => continue,
         };
-        let index = inliner.result.import_types.push((name.to_string(), ty));
+        let index = inliner
+            .result
+            .import_types
+            .push((name.as_str().to_string(), ty));
         let path = ImportPath::root(index);
-        args.insert(name, ComponentItemDef::from_import(path, ty)?);
+        args.insert(name.as_str(), ComponentItemDef::from_import(path, ty)?);
     }
 
     // This will run the inliner to completion after being seeded with the
@@ -376,7 +379,7 @@ impl<'a> Inliner<'a> {
             // but for sub-components this will do resolution to connect what
             // was provided as an import at the instantiation-site to what was
             // needed during the component's instantiation.
-            Import(name, _ty) => match &frame.args[name] {
+            Import(name, _ty) => match &frame.args[name.as_str()] {
                 ComponentItemDef::Module(i) => {
                     frame.modules.push(i.clone());
                 }
@@ -674,7 +677,7 @@ impl<'a> Inliner<'a> {
                     ComponentInstanceDef::Import(path, ty) => {
                         let mut path = path.clone();
                         path.path.push(name);
-                        match self.types[*ty].exports[*name].1 {
+                        match self.types[*ty].exports[*name] {
                             TypeDef::ComponentFunc(_) => {
                                 frame.component_funcs.push(ComponentFuncDef::Import(path));
                             }
@@ -939,7 +942,7 @@ impl<'a> Inliner<'a> {
                     // Note that for now this would only work with
                     // module-exporting instances.
                     ComponentInstanceDef::Import(path, ty) => {
-                        for (name, (_url, ty)) in self.types[ty].exports.iter() {
+                        for (name, ty) in self.types[ty].exports.iter() {
                             let mut path = path.clone();
                             path.path.push(name);
                             let def = ComponentItemDef::from_import(path, *ty)?;
diff --git a/crates/environ/src/component/types.rs b/crates/environ/src/component/types.rs
index d3424256e..e98271b4c 100644
--- a/crates/environ/src/component/types.rs
+++ b/crates/environ/src/component/types.rs
@@ -499,6 +499,9 @@ impl ComponentTypesBuilder {
                     let ty = TypeDef::CoreFunc(self.module_types.wasm_func_type(f));
                     self.push_core_typedef(ty);
                 }
+                wasmparser::ModuleTypeDeclaration::Type(wasmparser::Type::Array(_)) => {
+                    unimplemented!("gc types");
+                }
                 wasmparser::ModuleTypeDeclaration::Export { name, ty } => {
                     let prev = result
                         .exports
@@ -556,17 +559,13 @@ impl ComponentTypesBuilder {
                 ComponentTypeDeclaration::Type(ty) => self.type_declaration_type(ty)?,
                 ComponentTypeDeclaration::CoreType(ty) => self.type_declaration_core_type(ty)?,
                 ComponentTypeDeclaration::Alias(alias) => self.type_declaration_alias(alias)?,
-                ComponentTypeDeclaration::Export { name, url, ty } => {
+                ComponentTypeDeclaration::Export { name, ty } => {
                     let ty = self.type_declaration_define(ty);
-                    result
-                        .exports
-                        .insert(name.to_string(), (url.to_string(), ty));
+                    result.exports.insert(name.as_str().to_string(), ty);
                 }
                 ComponentTypeDeclaration::Import(import) => {
                     let ty = self.type_declaration_define(&import.ty);
-                    result
-                        .imports
-                        .insert(import.name.to_string(), (import.url.to_string(), ty));
+                    result.imports.insert(import.name.as_str().to_string(), ty);
                 }
             }
         }
@@ -588,11 +587,9 @@ impl ComponentTypesBuilder {
                 InstanceTypeDeclaration::Type(ty) => self.type_declaration_type(ty)?,
                 InstanceTypeDeclaration::CoreType(ty) => self.type_declaration_core_type(ty)?,
                 InstanceTypeDeclaration::Alias(alias) => self.type_declaration_alias(alias)?,
-                InstanceTypeDeclaration::Export { name, url, ty } => {
+                InstanceTypeDeclaration::Export { name, ty } => {
                     let ty = self.type_declaration_define(ty);
-                    result
-                        .exports
-                        .insert(name.to_string(), (url.to_string(), ty));
+                    result.exports.insert(name.as_str().to_string(), ty);
                 }
             }
         }
@@ -639,7 +636,7 @@ impl ComponentTypesBuilder {
             } => {
                 let ty = self.type_scopes.last().unwrap().instances
                     [ComponentInstanceIndex::from_u32(*instance_index)];
-                let (_, ty) = self.component_types[ty].exports[*name];
+                let ty = self.component_types[ty].exports[*name];
                 self.push_component_typedef(ty);
             }
             a => unreachable!("invalid alias {a:?}"),
@@ -1031,9 +1028,9 @@ pub struct TypeModule {
 #[derive(Serialize, Deserialize, Default)]
 pub struct TypeComponent {
     /// The named values that this component imports.
-    pub imports: IndexMap<String, (String, TypeDef)>,
+    pub imports: IndexMap<String, TypeDef>,
     /// The named values that this component exports.
-    pub exports: IndexMap<String, (String, TypeDef)>,
+    pub exports: IndexMap<String, TypeDef>,
 }
 
 /// The type of a component instance in the component model, or an instantiated
@@ -1043,7 +1040,7 @@ pub struct TypeComponent {
 #[derive(Serialize, Deserialize, Default)]
 pub struct TypeComponentInstance {
     /// The list of exports that this component has along with their types.
-    pub exports: IndexMap<String, (String, TypeDef)>,
+    pub exports: IndexMap<String, TypeDef>,
 }
 
 /// A component function type in the component model.
diff --git a/crates/environ/src/module_environ.rs b/crates/environ/src/module_environ.rs
index 06f8f158f..bfa81fd8b 100644
--- a/crates/environ/src/module_environ.rs
+++ b/crates/environ/src/module_environ.rs
@@ -243,6 +243,9 @@ impl<'a, 'data> ModuleEnvironment<'a, 'data> {
                             let ty = self.convert_func_type(&wasm_func_ty);
                             self.declare_type_func(ty)?;
                         }
+                        Type::Array(_) => {
+                            unimplemented!("gc proposal")
+                        }
                     }
                 }
             }
diff --git a/crates/types/src/lib.rs b/crates/types/src/lib.rs
index 68150ba63..0fbd34940 100644
--- a/crates/types/src/lib.rs
+++ b/crates/types/src/lib.rs
@@ -441,7 +441,7 @@ pub trait TypeConvert {
         match ty {
             wasmparser::HeapType::Func => WasmHeapType::Func,
             wasmparser::HeapType::Extern => WasmHeapType::Extern,
-            wasmparser::HeapType::TypedFunc(i) => self.lookup_heap_type(TypeIndex::from_u32(i)),
+            wasmparser::HeapType::Indexed(i) => self.lookup_heap_type(TypeIndex::from_u32(i)),
 
             wasmparser::HeapType::Any
             | wasmparser::HeapType::None
diff --git a/crates/wasi-http/src/lib.rs b/crates/wasi-http/src/lib.rs
index 4f90015cc..8f1ef030c 100644
--- a/crates/wasi-http/src/lib.rs
+++ b/crates/wasi-http/src/lib.rs
@@ -1,3 +1,7 @@
+// NB: this crate is temporarily disabled for a breaking change to WIT. This can
+// be re-enabled when the WIT in the wasi-http submodule is updated.
+#![cfg(FALSE)]
+
 use crate::component_impl::add_component_to_linker;
 pub use crate::r#struct::WasiHttp;
 
diff --git a/crates/wasi-preview1-component-adapter/Cargo.toml b/crates/wasi-preview1-component-adapter/Cargo.toml
index c2ca4c9c6..16af98f56 100644
--- a/crates/wasi-preview1-component-adapter/Cargo.toml
+++ b/crates/wasi-preview1-component-adapter/Cargo.toml
@@ -7,7 +7,7 @@ publish = false
 
 [dependencies]
 wasi = { version = "0.11.0", default-features = false }
-wit-bindgen = { version = "0.6.0", default-features = false, features = ["macros"] }
+wit-bindgen = { workspace = true, default-features = false, features = ["macros"] }
 byte-array-literals = { workspace = true }
 
 [build-dependencies]
diff --git a/crates/wasi-preview1-component-adapter/src/descriptors.rs b/crates/wasi-preview1-component-adapter/src/descriptors.rs
index 8b17ac7e6..cdeff8608 100644
--- a/crates/wasi-preview1-component-adapter/src/descriptors.rs
+++ b/crates/wasi-preview1-component-adapter/src/descriptors.rs
@@ -1,5 +1,7 @@
-use crate::bindings::streams::{self, InputStream, OutputStream};
-use crate::bindings::{filesystem, tcp};
+use crate::bindings::wasi::cli_base::{stderr, stdin, stdout};
+use crate::bindings::wasi::filesystem::filesystem;
+use crate::bindings::wasi::io::streams::{self, InputStream, OutputStream};
+use crate::bindings::wasi::sockets::tcp;
 use crate::{set_stderr_stream, BumpArena, File, ImportAlloc, TrappingUnwrap, WasmStr};
 use core::cell::{Cell, UnsafeCell};
 use core::mem::MaybeUninit;
@@ -140,9 +142,9 @@ impl Descriptors {
             preopens: Cell::new(None),
         };
 
-        let stdin = crate::bindings::stdin::get_stdin();
-        let stdout = crate::bindings::stdout::get_stdout();
-        let stderr = crate::bindings::stderr::get_stderr();
+        let stdin = stdin::get_stdin();
+        let stdout = stdout::get_stdout();
+        let stderr = stderr::get_stderr();
         unsafe { set_stderr_stream(stderr) };
 
         d.push(Descriptor::Streams(Streams {
@@ -164,7 +166,7 @@ impl Descriptors {
         }))
         .trapping_unwrap();
 
-        #[link(wasm_import_module = "preopens")]
+        #[link(wasm_import_module = "wasi:cli-base/preopens")]
         extern "C" {
             #[link_name = "get-directories"]
             fn get_preopens_import(rval: *mut PreopenList);
@@ -189,8 +191,7 @@ impl Descriptors {
                 output: Cell::new(None),
                 type_: StreamType::File(File {
                     fd: preopen.descriptor,
-                    descriptor_type: crate::bindings::filesystem::get_type(preopen.descriptor)
-                        .trapping_unwrap(),
+                    descriptor_type: filesystem::get_type(preopen.descriptor).trapping_unwrap(),
                     position: Cell::new(0),
                     append: false,
                     blocking: false,
@@ -346,7 +347,7 @@ impl Descriptors {
     }
 
     #[allow(dead_code)] // until Socket is implemented
-    pub fn get_socket(&self, fd: Fd) -> Result<crate::bindings::tcp::TcpSocket, Errno> {
+    pub fn get_socket(&self, fd: Fd) -> Result<tcp::TcpSocket, Errno> {
         match self.get(fd)? {
             Descriptor::Streams(Streams {
                 type_: StreamType::Socket(socket),
diff --git a/crates/wasi-preview1-component-adapter/src/lib.rs b/crates/wasi-preview1-component-adapter/src/lib.rs
index c368a57b2..d10fc48cd 100644
--- a/crates/wasi-preview1-component-adapter/src/lib.rs
+++ b/crates/wasi-preview1-component-adapter/src/lib.rs
@@ -1,8 +1,12 @@
 #![allow(unused_variables)] // TODO: remove this when more things are implemented
 
-use crate::bindings::{
-    exit, filesystem, monotonic_clock, network, poll, random, streams, wall_clock,
-};
+use crate::bindings::wasi::cli_base::exit;
+use crate::bindings::wasi::clocks::{monotonic_clock, wall_clock};
+use crate::bindings::wasi::filesystem::filesystem;
+use crate::bindings::wasi::io::streams;
+use crate::bindings::wasi::poll::poll;
+use crate::bindings::wasi::random::random;
+use crate::bindings::wasi::sockets::network;
 use core::cell::{Cell, RefCell, RefMut, UnsafeCell};
 use core::cmp::min;
 use core::ffi::c_void;
@@ -26,7 +30,8 @@ use crate::descriptors::{Descriptor, Descriptors, StreamType, Streams};
 pub mod bindings {
     #[cfg(feature = "command")]
     wit_bindgen::generate!({
-        world: "command",
+        path: "../wasi/wit",
+        world: "wasi:preview/command",
         std_feature,
         raw_strings,
         // The generated definition of command will pull in std, so we are defining it
@@ -36,7 +41,8 @@ pub mod bindings {
 
     #[cfg(feature = "reactor")]
     wit_bindgen::generate!({
-        world: "reactor",
+        path: "../wasi/wit",
+        world: "wasi:preview/reactor",
         std_feature,
         raw_strings,
         skip: ["get-directories", "get-environment"],
@@ -2335,7 +2341,7 @@ impl State {
 
     fn get_environment(&self) -> &[StrTuple] {
         if self.env_vars.get().is_none() {
-            #[link(wasm_import_module = "environment")]
+            #[link(wasm_import_module = "wasi:cli-base/environment")]
             extern "C" {
                 #[link_name = "get-environment"]
                 fn get_environment_import(rval: *mut StrTupleList);
@@ -2359,7 +2365,7 @@ impl State {
 
     fn get_args(&self) -> &[WasmStr] {
         if self.args.get().is_none() {
-            #[link(wasm_import_module = "environment")]
+            #[link(wasm_import_module = "wasi:cli-base/environment")]
             extern "C" {
                 #[link_name = "get-arguments"]
                 fn get_args_import(rval: *mut WasmStrList);
diff --git a/crates/wasi-preview1-component-adapter/src/macros.rs b/crates/wasi-preview1-component-adapter/src/macros.rs
index 13faf6bc6..ca46aacac 100644
--- a/crates/wasi-preview1-component-adapter/src/macros.rs
+++ b/crates/wasi-preview1-component-adapter/src/macros.rs
@@ -2,10 +2,13 @@
 //!
 //! We're avoiding static initializers, so we can't have things like string
 //! literals. Replace the standard assert macros with simpler implementations.
+
+use crate::bindings::wasi::io::streams;
+
 #[allow(dead_code)]
 #[doc(hidden)]
 pub fn print(message: &[u8]) {
-    let _ = unsafe { crate::bindings::streams::write(crate::get_stderr_stream(), message) };
+    let _ = unsafe { streams::write(crate::get_stderr_stream(), message) };
 }
 
 /// A minimal `eprint` for debugging.
diff --git a/crates/wasi-preview1-component-adapter/verify/src/main.rs b/crates/wasi-preview1-component-adapter/verify/src/main.rs
index 8fb23617f..2a8b391d7 100644
--- a/crates/wasi-preview1-component-adapter/verify/src/main.rs
+++ b/crates/wasi-preview1-component-adapter/verify/src/main.rs
@@ -2,31 +2,6 @@ use anyhow::{bail, Result};
 use std::env;
 use wasmparser::*;
 
-const ALLOWED_IMPORT_MODULES: &[&str] = &[
-    "wall-clock",
-    "monotonic-clock",
-    "timezone",
-    "filesystem",
-    "instance-network",
-    "ip-name-lookup",
-    "network",
-    "tcp-create-socket",
-    "tcp",
-    "udp-create-socket",
-    "udp",
-    "random",
-    "poll",
-    "streams",
-    "environment",
-    "preopens",
-    "exit",
-    "canonical_abi",
-    "stdin",
-    "stdout",
-    "stderr",
-    "__main_module__",
-];
-
 fn main() -> Result<()> {
     let file = env::args()
         .nth(1)
@@ -50,9 +25,13 @@ fn main() -> Result<()> {
                     let i = i?;
                     match i.ty {
                         TypeRef::Func(_) => {
-                            if !ALLOWED_IMPORT_MODULES.contains(&i.module) {
-                                bail!("import from unknown module `{}`", i.module);
+                            if i.module.starts_with("wasi:") {
+                                continue;
+                            }
+                            if i.module == "__main_module__" {
+                                continue;
                             }
+                            bail!("import from unknown module `{}`", i.module);
                         }
                         TypeRef::Table(_) => bail!("should not import table"),
                         TypeRef::Global(_) => bail!("should not import globals"),
diff --git a/crates/wasi-preview1-component-adapter/wit/deps/clocks/monotonic-clock.wit b/crates/wasi-preview1-component-adapter/wit/deps/clocks/monotonic-clock.wit
deleted file mode 100644
index 42e2981f5..000000000
--- a/crates/wasi-preview1-component-adapter/wit/deps/clocks/monotonic-clock.wit
+++ /dev/null
@@ -1,32 +0,0 @@
-/// WASI Monotonic Clock is a clock API intended to let users measure elapsed
-/// time.
-///
-/// It is intended to be portable at least between Unix-family platforms and
-/// Windows.
-///
-/// A monotonic clock is a clock which has an unspecified initial value, and
-/// successive reads of the clock will produce non-decreasing values.
-///
-/// It is intended for measuring elapsed time.
-default interface monotonic-clock {
-    use poll.poll.{pollable}
-
-    /// A timestamp in nanoseconds.
-    type instant = u64
-
-    /// Read the current value of the clock.
-    ///
-    /// The clock is monotonic, therefore calling this function repeatedly will
-    /// produce a sequence of non-decreasing values.
-    now: func() -> instant
-
-    /// Query the resolution of the clock.
-    resolution: func() -> instant
-
-    /// Create a `pollable` which will resolve once the specified time has been
-    /// reached.
-    subscribe: func(
-        when: instant,
-        absolute: bool
-    ) -> pollable
-}
diff --git a/crates/wasi-preview1-component-adapter/wit/deps/clocks/timezone.wit b/crates/wasi-preview1-component-adapter/wit/deps/clocks/timezone.wit
deleted file mode 100644
index 63f99cc40..000000000
--- a/crates/wasi-preview1-component-adapter/wit/deps/clocks/timezone.wit
+++ /dev/null
@@ -1,61 +0,0 @@
-default interface timezone {
-    use pkg.wall-clock.{datetime}
-
-    /// A timezone.
-    ///
-    /// In timezones that recognize daylight saving time, also known as daylight
-    /// time and summer time, the information returned from the functions varies
-    /// over time to reflect these adjustments.
-    ///
-    /// This [represents a resource](https://github.com/WebAssembly/WASI/blob/main/docs/WitInWasi.md#Resources).
-    type timezone = u32
-
-    /// Return information needed to display the given `datetime`. This includes
-    /// the UTC offset, the time zone name, and a flag indicating whether
-    /// daylight saving time is active.
-    ///
-    /// If the timezone cannot be determined for the given `datetime`, return a
-    /// `timezone-display` for `UTC` with a `utc-offset` of 0 and no daylight
-    /// saving time.
-    display: func(this: timezone, when: datetime) -> timezone-display
-
-    /// The same as `display`, but only return the UTC offset.
-    utc-offset: func(this: timezone, when: datetime) -> s32
-
-    /// Dispose of the specified input-stream, after which it may no longer
-    /// be used.
-    drop-timezone: func(this: timezone)
-
-    /// Information useful for displaying the timezone of a specific `datetime`.
-    ///
-    /// This information may vary within a single `timezone` to reflect daylight
-    /// saving time adjustments.
-    record timezone-display {
-        /// The number of seconds difference between UTC time and the local
-        /// time of the timezone.
-        ///
-        /// The returned value will always be less than 86400 which is the
-        /// number of seconds in a day (24*60*60).
-        ///
-        /// In implementations that do not expose an actual time zone, this
-        /// should return 0.
-        utc-offset: s32,
-
-        /// The abbreviated name of the timezone to display to a user. The name
-        /// `UTC` indicates Coordinated Universal Time. Otherwise, this should
-        /// reference local standards for the name of the time zone.
-        ///
-        /// In implementations that do not expose an actual time zone, this
-        /// should be the string `UTC`.
-        ///
-        /// In time zones that do not have an applicable name, a formatted
-        /// representation of the UTC offset may be returned, such as `-04:00`.
-        name: string,
-
-        /// Whether daylight saving time is active.
-        ///
-        /// In implementations that do not expose an actual time zone, this
-        /// should return false.
-        in-daylight-saving-time: bool,
-    }
-}
diff --git a/crates/wasi-preview1-component-adapter/wit/deps/clocks/wall-clock.wit b/crates/wasi-preview1-component-adapter/wit/deps/clocks/wall-clock.wit
deleted file mode 100644
index 89c5a75da..000000000
--- a/crates/wasi-preview1-component-adapter/wit/deps/clocks/wall-clock.wit
+++ /dev/null
@@ -1,41 +0,0 @@
-/// WASI Wall Clock is a clock API intended to let users query the current
-/// time. The name "wall" makes an analogy to a "clock on the wall", which
-/// is not necessarily monotonic as it may be reset.
-///
-/// It is intended to be portable at least between Unix-family platforms and
-/// Windows.
-///
-/// A wall clock is a clock which measures the date and time according to
-/// some external reference.
-///
-/// External references may be reset, so this clock is not necessarily
-/// monotonic, making it unsuitable for measuring elapsed time.
-///
-/// It is intended for reporting the current date and time for humans.
-default interface wall-clock {
-    /// A time and date in seconds plus nanoseconds.
-    record datetime {
-        seconds: u64,
-        nanoseconds: u32,
-    }
-
-    /// Read the current value of the clock.
-    ///
-    /// This clock is not monotonic, therefore calling this function repeatedly
-    /// will not necessarily produce a sequence of non-decreasing values.
-    ///
-    /// The returned timestamps represent the number of seconds since
-    /// 1970-01-01T00:00:00Z, also known as [POSIX's Seconds Since the Epoch],
-    /// also known as [Unix Time].
-    ///
-    /// The nanoseconds field of the output is always less than 1000000000.
-    ///
-    /// [POSIX's Seconds Since the Epoch]: https://pubs.opengroup.org/onlinepubs/9699919799/xrat/V4_xbd_chap04.html#tag_21_04_16
-    /// [Unix Time]: https://en.wikipedia.org/wiki/Unix_time
-    now: func() -> datetime
-
-    /// Query the resolution of the clock.
-    ///
-    /// The nanoseconds field of the output is always less than 1000000000.
-    resolution: func() -> datetime
-}
diff --git a/crates/wasi-preview1-component-adapter/wit/deps/http/incoming-handler.wit b/crates/wasi-preview1-component-adapter/wit/deps/http/incoming-handler.wit
deleted file mode 100644
index 1ecff0aa5..000000000
--- a/crates/wasi-preview1-component-adapter/wit/deps/http/incoming-handler.wit
+++ /dev/null
@@ -1,24 +0,0 @@
-// The `wasi:http/incoming-handler` interface is meant to be exported by
-// components and called by the host in response to a new incoming HTTP
-// response.
-//
-//   NOTE: in Preview3, this interface will be merged with
-//   `wasi:http/outgoing-handler` into a single `wasi:http/handler` interface
-//   that takes a `request` parameter and returns a `response` result.
-//
-default interface incoming-handler {
-  use pkg.types.{incoming-request, response-outparam}
-
-  // The `handle` function takes an outparam instead of returning its response
-  // so that the component may stream its response while streaming any other
-  // request or response bodies. The callee MUST write a response to the
-  // `response-out` and then finish the response before returning. The `handle`
-  // function is allowed to continue execution after finishing the response's
-  // output stream. While this post-response execution is taken off the
-  // critical path, since there is no return value, there is no way to report
-  // its success or failure.
-  handle: func(
-    request: incoming-request,
-    response-out: response-outparam
-  )
-}
diff --git a/crates/wasi-preview1-component-adapter/wit/deps/http/outgoing-handler.wit b/crates/wasi-preview1-component-adapter/wit/deps/http/outgoing-handler.wit
deleted file mode 100644
index abe812ffa..000000000
--- a/crates/wasi-preview1-component-adapter/wit/deps/http/outgoing-handler.wit
+++ /dev/null
@@ -1,18 +0,0 @@
-// The `wasi:http/outgoing-handler` interface is meant to be imported by
-// components and implemented by the host.
-//
-//   NOTE: in Preview3, this interface will be merged with
-//   `wasi:http/outgoing-handler` into a single `wasi:http/handler` interface
-//   that takes a `request` parameter and returns a `response` result.
-//
-default interface outgoing-handler {
-  use pkg.types.{outgoing-request, request-options, future-incoming-response}
-
-  // The parameter and result types of the `handle` function allow the caller
-  // to concurrently stream the bodies of the outgoing request and the incoming
-  // response.
-  handle: func(
-    request: outgoing-request,
-    options: option<request-options>
-  ) -> future-incoming-response
-}
diff --git a/crates/wasi-preview1-component-adapter/wit/deps/http/types.wit b/crates/wasi-preview1-component-adapter/wit/deps/http/types.wit
deleted file mode 100644
index bdcf79737..000000000
--- a/crates/wasi-preview1-component-adapter/wit/deps/http/types.wit
+++ /dev/null
@@ -1,157 +0,0 @@
-// The `wasi:http/types` interface is meant to be imported by components to
-// define the HTTP resource types and operations used by the component's
-// imported and exported interfaces.
-default interface types {
-  use io.streams.{input-stream, output-stream}
-  use poll.poll.{pollable}
-  
-  // This type corresponds to HTTP standard Methods.
-  variant method {
-    get,
-    head,
-    post,
-    put,
-    delete,
-    connect,
-    options,
-    trace,
-    patch,
-    other(string)
-  }
-
-  // This type corresponds to HTTP standard Related Schemes.
-  variant scheme {
-    HTTP,
-    HTTPS,
-    other(string)
-  }
-
-  // TODO: perhaps better align with HTTP semantics?
-  // This type enumerates the different kinds of errors that may occur when
-  // initially returning a response.
-  variant error {
-      invalid-url(string),
-      timeout-error(string),
-      protocol-error(string),
-      unexpected-error(string)
-  }
-
-  // This following block defines the `fields` resource which corresponds to
-  // HTTP standard Fields. Soon, when resource types are added, the `type
-  // fields = u32` type alias can be replaced by a proper `resource fields`
-  // definition containing all the functions using the method syntactic sugar.
-  type fields = u32
-  drop-fields: func(fields: fields)
-  new-fields: func(entries: list<tuple<string,string>>) -> fields
-  fields-get: func(fields: fields, name: string) -> list<string>
-  fields-set: func(fields: fields, name: string, value: list<string>)
-  fields-delete: func(fields: fields, name: string)
-  fields-append: func(fields: fields, name: string, value: string)
-  fields-entries: func(fields: fields) -> list<tuple<string,string>>
-  fields-clone: func(fields: fields) -> fields
-
-  type headers = fields
-  type trailers = fields
-
-  // The following block defines stream types which corresponds to the HTTP
-  // standard Contents and Trailers. With Preview3, all of these fields can be
-  // replaced by a stream<u8, option<trailers>>. In the interim, we need to
-  // build on separate resource types defined by `wasi:io/streams`. The
-  // `finish-` functions emulate the stream's result value and MUST be called
-  // exactly once after the final read/write from/to the stream before dropping
-  // the stream.
-  type incoming-stream = input-stream
-  type outgoing-stream = output-stream
-  finish-incoming-stream: func(s: incoming-stream) -> option<trailers>
-  finish-outgoing-stream: func(s: outgoing-stream, trailers: option<trailers>)
-
-  // The following block defines the `incoming-request` and `outgoing-request`
-  // resource types that correspond to HTTP standard Requests. Soon, when
-  // resource types are added, the `u32` type aliases can be replaced by
-  // proper `resource` type definitions containing all the functions as
-  // methods. Later, Preview2 will allow both types to be merged together into
-  // a single `request` type (that uses the single `stream` type mentioned
-  // above). The `consume` and `write` methods may only be called once (and
-  // return failure thereafter).
-  type incoming-request = u32
-  type outgoing-request = u32
-  drop-incoming-request: func(request: incoming-request)
-  drop-outgoing-request: func(request: outgoing-request)
-  incoming-request-method: func(request: incoming-request) -> method
-  incoming-request-path: func(request: incoming-request) -> string
-  incoming-request-query: func(request: incoming-request) -> string
-  incoming-request-scheme: func(request: incoming-request) -> option<scheme>
-  incoming-request-authority: func(request: incoming-request) -> string
-  incoming-request-headers: func(request: incoming-request) -> headers
-  incoming-request-consume: func(request: incoming-request) -> result<incoming-stream>
-  new-outgoing-request: func(
-    method: method,
-    path: string,
-    query: string,
-    scheme: option<scheme>,
-    authority: string,
-    headers: headers
-  ) -> outgoing-request
-  outgoing-request-write: func(request: outgoing-request) -> result<outgoing-stream>
-
-  // Additional optional parameters that can be set when making a request.
-  record request-options {
-    // The following timeouts are specific to the HTTP protocol and work
-    // independently of the overall timeouts passed to `io.poll.poll-oneoff`.
-
-    // The timeout for the initial connect.
-    connect-timeout-ms: option<u32>,
-
-    // The timeout for receiving the first byte of the response body.
-    first-byte-timeout-ms: option<u32>,
-
-    // The timeout for receiving the next chunk of bytes in the response body
-    // stream.
-    between-bytes-timeout-ms: option<u32>
-  }
-
-  // The following block defines a special resource type used by the
-  // `wasi:http/incoming-handler` interface. When resource types are added, this
-  // block can be replaced by a proper `resource response-outparam { ... }`
-  // definition. Later, with Preview3, the need for an outparam goes away entirely
-  // (the `wasi:http/handler` interface used for both incoming and outgoing can
-  // simply return a `stream`).
-  type response-outparam = u32
-  drop-response-outparam: func(response: response-outparam)
-  set-response-outparam: func(response: result<outgoing-response, error>) -> result
-
-  // This type corresponds to the HTTP standard Status Code.
-  type status-code = u16
-
-  // The following block defines the `incoming-response` and `outgoing-response`
-  // resource types that correspond to HTTP standard Responses. Soon, when
-  // resource types are added, the `u32` type aliases can be replaced by proper
-  // `resource` type definitions containing all the functions as methods. Later,
-  // Preview2 will allow both types to be merged together into a single `response`
-  // type (that uses the single `stream` type mentioned above). The `consume` and
-  // `write` methods may only be called once (and return failure thereafter).
-  type incoming-response = u32
-  type outgoing-response = u32
-  drop-incoming-response: func(response: incoming-response)
-  drop-outgoing-response: func(response: outgoing-response)
-  incoming-response-status: func(response: incoming-response) -> status-code
-  incoming-response-headers: func(response: incoming-response) -> headers
-  incoming-response-consume: func(response: incoming-response) -> result<incoming-stream>
-  new-outgoing-response: func(
-    status-code: status-code,
-    headers: headers
-  ) -> outgoing-response
-  outgoing-response-write: func(response: outgoing-response) -> result<outgoing-stream>
-
-  // The following block defines a special resource type used by the
-  // `wasi:http/outgoing-handler` interface to emulate
-  // `future<result<response, error>>` in advance of Preview3. Given a
-  // `future-incoming-response`, the client can call the non-blocking `get`
-  // method to get the result if it is available. If the result is not available,
-  // the client can call `listen` to get a `pollable` that can be passed to
-  // `io.poll.poll-oneoff`.
-  type future-incoming-response = u32
-  drop-future-incoming-response: func(f: future-incoming-response)
-  future-incoming-response-get: func(f: future-incoming-response) -> option<result<incoming-response, error>>
-  listen-to-future-incoming-response: func(f: future-incoming-response) -> pollable
-}
diff --git a/crates/wasi-preview1-component-adapter/wit/deps/io/streams.wit b/crates/wasi-preview1-component-adapter/wit/deps/io/streams.wit
deleted file mode 100644
index c1567fd4c..000000000
--- a/crates/wasi-preview1-component-adapter/wit/deps/io/streams.wit
+++ /dev/null
@@ -1,213 +0,0 @@
-/// WASI I/O is an I/O abstraction API which is currently focused on providing
-/// stream types.
-///
-/// In the future, the component model is expected to add built-in stream types;
-/// when it does, they are expected to subsume this API.
-default interface streams {
-    use poll.poll.{pollable}
-
-    /// An error type returned from a stream operation. Currently this
-    /// doesn't provide any additional information.
-    record stream-error {}
-
-    /// An input bytestream. In the future, this will be replaced by handle
-    /// types.
-    ///
-    /// This conceptually represents a `stream<u8, _>`. It's temporary
-    /// scaffolding until component-model's async features are ready.
-    ///
-    /// `input-stream`s are *non-blocking* to the extent practical on underlying
-    /// platforms. I/O operations always return promptly; if fewer bytes are
-    /// promptly available than requested, they return the number of bytes promptly
-    /// available, which could even be zero. To wait for data to be available,
-    /// use the `subscribe-to-input-stream` function to obtain a `pollable` which
-    /// can be polled for using `wasi_poll`.
-    ///
-    /// And at present, it is a `u32` instead of being an actual handle, until
-    /// the wit-bindgen implementation of handles and resources is ready.
-    ///
-    /// This [represents a resource](https://github.com/WebAssembly/WASI/blob/main/docs/WitInWasi.md#Resources).
-    type input-stream = u32
-
-    /// Read bytes from a stream.
-    ///
-    /// This function returns a list of bytes containing the data that was
-    /// read, along with a bool which, when true, indicates that the end of the
-    /// stream was reached. The returned list will contain up to `len` bytes; it
-    /// may return fewer than requested, but not more.
-    ///
-    /// Once a stream has reached the end, subsequent calls to read or
-    /// `skip` will always report end-of-stream rather than producing more
-    /// data.
-    ///
-    /// If `len` is 0, it represents a request to read 0 bytes, which should
-    /// always succeed, assuming the stream hasn't reached its end yet, and
-    /// return an empty list.
-    ///
-    /// The len here is a `u64`, but some callees may not be able to allocate
-    /// a buffer as large as that would imply.
-    /// FIXME: describe what happens if allocation fails.
-    read: func(
-        this: input-stream,
-        /// The maximum number of bytes to read
-        len: u64
-    ) -> result<tuple<list<u8>, bool>, stream-error>
-
-    /// Read bytes from a stream, with blocking.
-    ///
-    /// This is similar to `read`, except that it blocks until at least one
-    /// byte can be read.
-    blocking-read: func(
-        this: input-stream,
-        /// The maximum number of bytes to read
-        len: u64
-    ) -> result<tuple<list<u8>, bool>, stream-error>
-
-    /// Skip bytes from a stream.
-    ///
-    /// This is similar to the `read` function, but avoids copying the
-    /// bytes into the instance.
-    ///
-    /// Once a stream has reached the end, subsequent calls to read or
-    /// `skip` will always report end-of-stream rather than producing more
-    /// data.
-    ///
-    /// This function returns the number of bytes skipped, along with a bool
-    /// indicating whether the end of the stream was reached. The returned
-    /// value will be at most `len`; it may be less.
-    skip: func(
-        this: input-stream,
-        /// The maximum number of bytes to skip.
-        len: u64,
-    ) -> result<tuple<u64, bool>, stream-error>
-
-    /// Skip bytes from a stream, with blocking.
-    ///
-    /// This is similar to `skip`, except that it blocks until at least one
-    /// byte can be consumed.
-    blocking-skip: func(
-        this: input-stream,
-        /// The maximum number of bytes to skip.
-        len: u64,
-    ) -> result<tuple<u64, bool>, stream-error>
-
-    /// Create a `pollable` which will resolve once either the specified stream
-    /// has bytes available to read or the other end of the stream has been
-    /// closed.
-    subscribe-to-input-stream: func(this: input-stream) -> pollable
-
-    /// Dispose of the specified `input-stream`, after which it may no longer
-    /// be used.
-    drop-input-stream: func(this: input-stream)
-
-    /// An output bytestream. In the future, this will be replaced by handle
-    /// types.
-    ///
-    /// This conceptually represents a `stream<u8, _>`. It's temporary
-    /// scaffolding until component-model's async features are ready.
-    ///
-    /// `output-stream`s are *non-blocking* to the extent practical on
-    /// underlying platforms. Except where specified otherwise, I/O operations also
-    /// always return promptly, after the number of bytes that can be written
-    /// promptly, which could even be zero. To wait for the stream to be ready to
-    /// accept data, the `subscribe-to-output-stream` function to obtain a
-    /// `pollable` which can be polled for using `wasi_poll`.
-    ///
-    /// And at present, it is a `u32` instead of being an actual handle, until
-    /// the wit-bindgen implementation of handles and resources is ready.
-    ///
-    /// This [represents a resource](https://github.com/WebAssembly/WASI/blob/main/docs/WitInWasi.md#Resources).
-    type output-stream = u32
-
-    /// Write bytes to a stream.
-    ///
-    /// This function returns a `u64` indicating the number of bytes from
-    /// `buf` that were written; it may be less than the full list.
-    write: func(
-        this: output-stream,
-        /// Data to write
-        buf: list<u8>
-    ) -> result<u64, stream-error>
-
-    /// Write bytes to a stream, with blocking.
-    ///
-    /// This is similar to `write`, except that it blocks until at least one
-    /// byte can be written.
-    blocking-write: func(
-        this: output-stream,
-        /// Data to write
-        buf: list<u8>
-    ) -> result<u64, stream-error>
-
-    /// Write multiple zero bytes to a stream.
-    ///
-    /// This function returns a `u64` indicating the number of zero bytes
-    /// that were written; it may be less than `len`.
-    write-zeroes: func(
-        this: output-stream,
-        /// The number of zero bytes to write
-        len: u64
-    ) -> result<u64, stream-error>
-
-    /// Write multiple zero bytes to a stream, with blocking.
-    ///
-    /// This is similar to `write-zeroes`, except that it blocks until at least
-    /// one byte can be written.
-    blocking-write-zeroes: func(
-        this: output-stream,
-        /// The number of zero bytes to write
-        len: u64
-    ) -> result<u64, stream-error>
-
-    /// Read from one stream and write to another.
-    ///
-    /// This function returns the number of bytes transferred; it may be less
-    /// than `len`.
-    ///
-    /// Unlike other I/O functions, this function blocks until all the data
-    /// read from the input stream has been written to the output stream.
-    splice: func(
-        this: output-stream,
-        /// The stream to read from
-        src: input-stream,
-        /// The number of bytes to splice
-        len: u64,
-    ) -> result<tuple<u64, bool>, stream-error>
-
-    /// Read from one stream and write to another, with blocking.
-    ///
-    /// This is similar to `splice`, except that it blocks until at least
-    /// one byte can be read.
-    blocking-splice: func(
-        this: output-stream,
-        /// The stream to read from
-        src: input-stream,
-        /// The number of bytes to splice
-        len: u64,
-    ) -> result<tuple<u64, bool>, stream-error>
-
-    /// Forward the entire contents of an input stream to an output stream.
-    ///
-    /// This function repeatedly reads from the input stream and writes
-    /// the data to the output stream, until the end of the input stream
-    /// is reached, or an error is encountered.
-    ///
-    /// Unlike other I/O functions, this function blocks until the end
-    /// of the input stream is seen and all the data has been written to
-    /// the output stream.
-    ///
-    /// This function returns the number of bytes transferred.
-    forward: func(
-        this: output-stream,
-        /// The stream to read from
-        src: input-stream
-    ) -> result<u64, stream-error>
-
-    /// Create a `pollable` which will resolve once either the specified stream
-    /// is ready to accept bytes or the other end of the stream has been closed.
-    subscribe-to-output-stream: func(this: output-stream) -> pollable
-
-    /// Dispose of the specified `output-stream`, after which it may no longer
-    /// be used.
-    drop-output-stream: func(this: output-stream)
-}
diff --git a/crates/wasi-preview1-component-adapter/wit/deps/logging/handler.wit b/crates/wasi-preview1-component-adapter/wit/deps/logging/handler.wit
deleted file mode 100644
index c9632b9cc..000000000
--- a/crates/wasi-preview1-component-adapter/wit/deps/logging/handler.wit
+++ /dev/null
@@ -1,32 +0,0 @@
-/// WASI Logging is a logging API intended to let users emit log messages with
-/// simple priority levels and context values.
-default interface handler {
-    /// A log level, describing a kind of message.
-    enum level {
-       /// Describes messages about the values of variables and the flow of
-       /// control within a program.
-       trace,
-
-       /// Describes messages likely to be of interest to someone debugging a
-       /// program.
-       debug,
-
-       /// Describes messages likely to be of interest to someone monitoring a
-       /// program.
-       info,
-
-       /// Describes messages indicating hazardous situations.
-       warn,
-
-       /// Describes messages indicating serious errors.
-       error,
-    }
-
-    /// Emit a log message.
-    ///
-    /// A log message has a `level` describing what kind of message is being
-    /// sent, a context, which is an uninterpreted string meant to help
-    /// consumers group similar messages, and a string containing the message
-    /// text.
-    log: func(level: level, context: string, message: string)
-}
diff --git a/crates/wasi-preview1-component-adapter/wit/deps/poll/poll.wit b/crates/wasi-preview1-component-adapter/wit/deps/poll/poll.wit
deleted file mode 100644
index 28f08e17d..000000000
--- a/crates/wasi-preview1-component-adapter/wit/deps/poll/poll.wit
+++ /dev/null
@@ -1,39 +0,0 @@
-/// A poll API intended to let users wait for I/O events on multiple handles
-/// at once.
-default interface poll {
-    /// A "pollable" handle.
-    ///
-    /// This is conceptually represents a `stream<_, _>`, or in other words,
-    /// a stream that one can wait on, repeatedly, but which does not itself
-    /// produce any data. It's temporary scaffolding until component-model's
-    /// async features are ready.
-    ///
-    /// And at present, it is a `u32` instead of being an actual handle, until
-    /// the wit-bindgen implementation of handles and resources is ready.
-    ///
-    /// `pollable` lifetimes are not automatically managed. Users must ensure
-    /// that they do not outlive the resource they reference.
-    ///
-    /// This [represents a resource](https://github.com/WebAssembly/WASI/blob/main/docs/WitInWasi.md#Resources).
-    type pollable = u32
-
-    /// Dispose of the specified `pollable`, after which it may no longer
-    /// be used.
-    drop-pollable: func(this: pollable)
-
-    /// Poll for completion on a set of pollables.
-    ///
-    /// The "oneoff" in the name refers to the fact that this function must do a
-    /// linear scan through the entire list of subscriptions, which may be
-    /// inefficient if the number is large and the same subscriptions are used
-    /// many times. In the future, this is expected to be obsoleted by the
-    /// component model async proposal, which will include a scalable waiting
-    /// facility.
-    ///
-    /// Note that the return type would ideally be `list<bool>`, but that would
-    /// be more difficult to polyfill given the current state of `wit-bindgen`.
-    /// See <https://github.com/bytecodealliance/preview2-prototyping/pull/11#issuecomment-1329873061>
-    /// for details.  For now, we use zero to mean "not ready" and non-zero to
-    /// mean "ready".
-    poll-oneoff: func(in: list<pollable>) -> list<u8>
-}
diff --git a/crates/wasi-preview1-component-adapter/wit/deps/preview/reactor.wit b/crates/wasi-preview1-component-adapter/wit/deps/preview/reactor.wit
deleted file mode 100644
index 2abfa466b..000000000
--- a/crates/wasi-preview1-component-adapter/wit/deps/preview/reactor.wit
+++ /dev/null
@@ -1,21 +0,0 @@
-default world reactor {
-  import wall-clock: clocks.wall-clock
-  import monotonic-clock: clocks.monotonic-clock
-  import timezone: clocks.timezone
-  import filesystem: filesystem.filesystem
-  import instance-network: sockets.instance-network
-  import ip-name-lookup: sockets.ip-name-lookup
-  import network: sockets.network
-  import tcp-create-socket: sockets.tcp-create-socket
-  import tcp: sockets.tcp
-  import udp-create-socket: sockets.udp-create-socket
-  import udp: sockets.udp
-  import random: random.random
-  import poll: poll.poll
-  import streams: io.streams
-  import console: logging.handler
-  import default-outgoing-HTTP: http.outgoing-handler
-  import environment: wasi-cli-base.environment
-  import preopens: wasi-cli-base.preopens
-  import exit: wasi-cli-base.exit
-}
diff --git a/crates/wasi-preview1-component-adapter/wit/deps/sockets/instance-network.wit b/crates/wasi-preview1-component-adapter/wit/deps/sockets/instance-network.wit
deleted file mode 100644
index b1f5c982d..000000000
--- a/crates/wasi-preview1-component-adapter/wit/deps/sockets/instance-network.wit
+++ /dev/null
@@ -1,9 +0,0 @@
-
-/// This interface provides a value-export of the default network handle..
-default interface instance-network {
-	use pkg.network.{network}
-
-	/// Get a handle to the default network.
-	instance-network: func() -> network
-
-}
diff --git a/crates/wasi-preview1-component-adapter/wit/deps/wasi-cli-base/environment.wit b/crates/wasi-preview1-component-adapter/wit/deps/wasi-cli-base/environment.wit
deleted file mode 100644
index 876ea3a0c..000000000
--- a/crates/wasi-preview1-component-adapter/wit/deps/wasi-cli-base/environment.wit
+++ /dev/null
@@ -1,14 +0,0 @@
-default interface environment {
-  /// Get the POSIX-style environment variables.
-  ///
-  /// Each environment variable is provided as a pair of string variable names
-  /// and string value.
-  ///
-  /// Morally, these are a value import, but until value imports are available
-  /// in the component model, this import function should return the same
-  /// values each time it is called.
-  get-environment: func() -> list<tuple<string, string>>
-
-  /// Get the POSIX-style arguments to the program.
-  get-arguments: func() -> list<string>
-}
diff --git a/crates/wasi-preview1-component-adapter/wit/deps/wasi-cli-base/exit.wit b/crates/wasi-preview1-component-adapter/wit/deps/wasi-cli-base/exit.wit
deleted file mode 100644
index 2759e9dd9..000000000
--- a/crates/wasi-preview1-component-adapter/wit/deps/wasi-cli-base/exit.wit
+++ /dev/null
@@ -1,4 +0,0 @@
-default interface wasi-exit {
-  /// Exit the curerent instance and any linked instances.
-  exit: func(status: result)
-}
diff --git a/crates/wasi/src/preview2/preview1/mod.rs b/crates/wasi/src/preview2/preview1/mod.rs
index 3fb1a5806..9040425ac 100644
--- a/crates/wasi/src/preview2/preview1/mod.rs
+++ b/crates/wasi/src/preview2/preview1/mod.rs
@@ -1,25 +1,27 @@
 use crate::preview2::filesystem::TableFsExt;
 use crate::preview2::preview2::filesystem::TableReaddirExt;
+use crate::preview2::wasi::cli_base::{preopens, stderr, stdin, stdout};
+use crate::preview2::wasi::clocks::monotonic_clock;
+use crate::preview2::wasi::clocks::wall_clock;
+use crate::preview2::wasi::filesystem::filesystem;
+use crate::preview2::wasi::io::streams;
 use crate::preview2::{wasi, TableError, WasiView};
-
-use core::borrow::Borrow;
-use core::cell::Cell;
-use core::mem::{size_of, size_of_val};
-use core::ops::{Deref, DerefMut};
-use core::slice;
-use core::sync::atomic::{AtomicU64, Ordering};
-
+use anyhow::{anyhow, bail, Context};
+use std::borrow::Borrow;
+use std::cell::Cell;
 use std::collections::BTreeMap;
+use std::mem::{size_of, size_of_val};
+use std::ops::{Deref, DerefMut};
+use std::slice;
+use std::sync::atomic::{AtomicU64, Ordering};
 use std::sync::Arc;
-
-use anyhow::{anyhow, bail, Context};
 use wiggle::tracing::instrument;
 use wiggle::{GuestPtr, GuestSliceMut, GuestStrCow, GuestType};
 
 #[derive(Clone, Debug)]
 struct File {
     /// The handle to the preview2 descriptor that this file is referencing.
-    fd: wasi::filesystem::Descriptor,
+    fd: filesystem::Descriptor,
 
     /// The current-position pointer.
     position: Arc<AtomicU64>,
@@ -35,10 +37,10 @@ struct File {
 
 #[derive(Clone, Debug)]
 enum Descriptor {
-    Stdin(wasi::preopens::InputStream),
-    Stdout(wasi::preopens::OutputStream),
-    Stderr(wasi::preopens::OutputStream),
-    PreopenDirectory((wasi::filesystem::Descriptor, String)),
+    Stdin(preopens::InputStream),
+    Stdout(preopens::OutputStream),
+    Stderr(preopens::OutputStream),
+    PreopenDirectory((filesystem::Descriptor, String)),
     File(File),
 }
 
@@ -70,11 +72,7 @@ impl DerefMut for Descriptors {
 impl Descriptors {
     /// Initializes [Self] using `preopens`
     async fn new(
-        preopens: &mut (impl wasi::preopens::Host
-                  + wasi::stdin::Host
-                  + wasi::stdout::Host
-                  + wasi::stderr::Host
-                  + ?Sized),
+        preopens: &mut (impl preopens::Host + stdin::Host + stdout::Host + stderr::Host + ?Sized),
     ) -> Result<Self, types::Error> {
         let stdin = preopens
             .get_stdin()
@@ -245,8 +243,8 @@ impl<T: WasiPreview1View + ?Sized> Transaction<'_, T> {
         }
     }
 
-    /// Returns [`wasi::filesystem::Descriptor`] corresponding to `fd`
-    fn get_fd(&mut self, fd: types::Fd) -> ErrnoResult<wasi::filesystem::Descriptor> {
+    /// Returns [`filesystem::Descriptor`] corresponding to `fd`
+    fn get_fd(&mut self, fd: types::Fd) -> ErrnoResult<filesystem::Descriptor> {
         match self.get_descriptor(fd)? {
             Descriptor::File(File { fd, .. }) => Ok(*fd),
             Descriptor::PreopenDirectory((fd, _)) => Ok(*fd),
@@ -255,16 +253,16 @@ impl<T: WasiPreview1View + ?Sized> Transaction<'_, T> {
         }
     }
 
-    /// Returns [`wasi::filesystem::Descriptor`] corresponding to `fd`
+    /// Returns [`filesystem::Descriptor`] corresponding to `fd`
     /// if it describes a [`Descriptor::File`] of [`crate::preview2::filesystem::File`] type
-    fn get_file_fd(&mut self, fd: types::Fd) -> ErrnoResult<wasi::filesystem::Descriptor> {
+    fn get_file_fd(&mut self, fd: types::Fd) -> ErrnoResult<filesystem::Descriptor> {
         self.get_file(fd).map(|File { fd, .. }| *fd)
     }
 
-    /// Returns [`wasi::filesystem::Descriptor`] corresponding to `fd`
+    /// Returns [`filesystem::Descriptor`] corresponding to `fd`
     /// if it describes a [`Descriptor::File`] or [`Descriptor::PreopenDirectory`]
     /// of [`crate::preview2::filesystem::Dir`] type
-    fn get_dir_fd(&mut self, fd: types::Fd) -> ErrnoResult<wasi::filesystem::Descriptor> {
+    fn get_dir_fd(&mut self, fd: types::Fd) -> ErrnoResult<filesystem::Descriptor> {
         let fd = fd.into();
         match self.descriptors.get_mut().get(&fd) {
             Some(Descriptor::File(File { fd, .. })) if self.view.table().is_dir(*fd) => Ok(*fd),
@@ -276,11 +274,7 @@ impl<T: WasiPreview1View + ?Sized> Transaction<'_, T> {
 
 #[wiggle::async_trait]
 trait WasiPreview1ViewExt:
-    WasiPreview1View
-    + wasi::preopens::Host
-    + wasi::stdin::Host
-    + wasi::stdout::Host
-    + wasi::stderr::Host
+    WasiPreview1View + preopens::Host + stdin::Host + stdout::Host + stderr::Host
 {
     /// Lazily initializes [`WasiPreview1Adapter`] returned by [`WasiPreview1View::adapter_mut`]
     /// and returns [`Transaction`] on success
@@ -298,55 +292,46 @@ trait WasiPreview1ViewExt:
     }
 
     /// Lazily initializes [`WasiPreview1Adapter`] returned by [`WasiPreview1View::adapter_mut`]
-    /// and returns [`wasi::filesystem::Descriptor`] corresponding to `fd`
-    async fn get_fd(
-        &mut self,
-        fd: types::Fd,
-    ) -> Result<wasi::filesystem::Descriptor, types::Error> {
+    /// and returns [`filesystem::Descriptor`] corresponding to `fd`
+    async fn get_fd(&mut self, fd: types::Fd) -> Result<filesystem::Descriptor, types::Error> {
         let mut st = self.transact().await?;
         let fd = st.get_fd(fd)?;
         Ok(fd)
     }
 
     /// Lazily initializes [`WasiPreview1Adapter`] returned by [`WasiPreview1View::adapter_mut`]
-    /// and returns [`wasi::filesystem::Descriptor`] corresponding to `fd`
+    /// and returns [`filesystem::Descriptor`] corresponding to `fd`
     /// if it describes a [`Descriptor::File`] of [`crate::preview2::filesystem::File`] type
-    async fn get_file_fd(
-        &mut self,
-        fd: types::Fd,
-    ) -> Result<wasi::filesystem::Descriptor, types::Error> {
+    async fn get_file_fd(&mut self, fd: types::Fd) -> Result<filesystem::Descriptor, types::Error> {
         let mut st = self.transact().await?;
         let fd = st.get_file_fd(fd)?;
         Ok(fd)
     }
 
     /// Lazily initializes [`WasiPreview1Adapter`] returned by [`WasiPreview1View::adapter_mut`]
-    /// and returns [`wasi::filesystem::Descriptor`] corresponding to `fd`
+    /// and returns [`filesystem::Descriptor`] corresponding to `fd`
     /// if it describes a [`Descriptor::File`] or [`Descriptor::PreopenDirectory`]
     /// of [`crate::preview2::filesystem::Dir`] type
-    async fn get_dir_fd(
-        &mut self,
-        fd: types::Fd,
-    ) -> Result<wasi::filesystem::Descriptor, types::Error> {
+    async fn get_dir_fd(&mut self, fd: types::Fd) -> Result<filesystem::Descriptor, types::Error> {
         let mut st = self.transact().await?;
         let fd = st.get_dir_fd(fd)?;
         Ok(fd)
     }
 }
 
-impl<T: WasiPreview1View + wasi::preopens::Host> WasiPreview1ViewExt for T {}
+impl<T: WasiPreview1View + preopens::Host> WasiPreview1ViewExt for T {}
 
 pub fn add_to_linker<
     T: WasiPreview1View
-        + wasi::environment::Host
-        + wasi::exit::Host
-        + wasi::filesystem::Host
-        + wasi::monotonic_clock::Host
-        + wasi::poll::Host
-        + wasi::preopens::Host
-        + wasi::random::Host
-        + wasi::streams::Host
-        + wasi::wall_clock::Host,
+        + wasi::cli_base::environment::Host
+        + wasi::cli_base::exit::Host
+        + wasi::cli_base::preopens::Host
+        + wasi::filesystem::filesystem::Host
+        + wasi::poll::poll::Host
+        + wasi::random::random::Host
+        + wasi::io::streams::Host
+        + wasi::clocks::monotonic_clock::Host
+        + wasi::clocks::wall_clock::Host,
 >(
     linker: &mut wasmtime::Linker<T>,
 ) -> anyhow::Result<()> {
@@ -373,31 +358,29 @@ fn systimespec(
     set: bool,
     ts: types::Timestamp,
     now: bool,
-) -> ErrnoResult<wasi::filesystem::NewTimestamp> {
+) -> ErrnoResult<filesystem::NewTimestamp> {
     if set && now {
         Err(types::Errno::Inval)
     } else if set {
-        Ok(wasi::filesystem::NewTimestamp::Timestamp(
-            wasi::filesystem::Datetime {
-                seconds: ts / 1_000_000_000,
-                nanoseconds: (ts % 1_000_000_000) as _,
-            },
-        ))
+        Ok(filesystem::NewTimestamp::Timestamp(filesystem::Datetime {
+            seconds: ts / 1_000_000_000,
+            nanoseconds: (ts % 1_000_000_000) as _,
+        }))
     } else if now {
-        Ok(wasi::filesystem::NewTimestamp::Now)
+        Ok(filesystem::NewTimestamp::Now)
     } else {
-        Ok(wasi::filesystem::NewTimestamp::NoChange)
+        Ok(filesystem::NewTimestamp::NoChange)
     }
 }
 
-impl TryFrom<wasi::wall_clock::Datetime> for types::Timestamp {
+impl TryFrom<wall_clock::Datetime> for types::Timestamp {
     type Error = types::Errno;
 
     fn try_from(
-        wasi::wall_clock::Datetime {
+        wall_clock::Datetime {
             seconds,
             nanoseconds,
-        }: wasi::wall_clock::Datetime,
+        }: wall_clock::Datetime,
     ) -> Result<Self, Self::Error> {
         types::Timestamp::from(seconds)
             .checked_mul(1_000_000_000)
@@ -406,126 +389,124 @@ impl TryFrom<wasi::wall_clock::Datetime> for types::Timestamp {
     }
 }
 
-impl From<types::Lookupflags> for wasi::filesystem::PathFlags {
+impl From<types::Lookupflags> for filesystem::PathFlags {
     fn from(flags: types::Lookupflags) -> Self {
         if flags.contains(types::Lookupflags::SYMLINK_FOLLOW) {
-            wasi::filesystem::PathFlags::SYMLINK_FOLLOW
+            filesystem::PathFlags::SYMLINK_FOLLOW
         } else {
-            wasi::filesystem::PathFlags::empty()
+            filesystem::PathFlags::empty()
         }
     }
 }
 
-impl From<types::Oflags> for wasi::filesystem::OpenFlags {
+impl From<types::Oflags> for filesystem::OpenFlags {
     fn from(flags: types::Oflags) -> Self {
-        let mut out = wasi::filesystem::OpenFlags::empty();
+        let mut out = filesystem::OpenFlags::empty();
         if flags.contains(types::Oflags::CREAT) {
-            out |= wasi::filesystem::OpenFlags::CREATE;
+            out |= filesystem::OpenFlags::CREATE;
         }
         if flags.contains(types::Oflags::DIRECTORY) {
-            out |= wasi::filesystem::OpenFlags::DIRECTORY;
+            out |= filesystem::OpenFlags::DIRECTORY;
         }
         if flags.contains(types::Oflags::EXCL) {
-            out |= wasi::filesystem::OpenFlags::EXCLUSIVE;
+            out |= filesystem::OpenFlags::EXCLUSIVE;
         }
         if flags.contains(types::Oflags::TRUNC) {
-            out |= wasi::filesystem::OpenFlags::TRUNCATE;
+            out |= filesystem::OpenFlags::TRUNCATE;
         }
         out
     }
 }
 
-impl From<types::Advice> for wasi::filesystem::Advice {
+impl From<types::Advice> for filesystem::Advice {
     fn from(advice: types::Advice) -> Self {
         match advice {
-            types::Advice::Normal => wasi::filesystem::Advice::Normal,
-            types::Advice::Sequential => wasi::filesystem::Advice::Sequential,
-            types::Advice::Random => wasi::filesystem::Advice::Random,
-            types::Advice::Willneed => wasi::filesystem::Advice::WillNeed,
-            types::Advice::Dontneed => wasi::filesystem::Advice::DontNeed,
-            types::Advice::Noreuse => wasi::filesystem::Advice::NoReuse,
+            types::Advice::Normal => filesystem::Advice::Normal,
+            types::Advice::Sequential => filesystem::Advice::Sequential,
+            types::Advice::Random => filesystem::Advice::Random,
+            types::Advice::Willneed => filesystem::Advice::WillNeed,
+            types::Advice::Dontneed => filesystem::Advice::DontNeed,
+            types::Advice::Noreuse => filesystem::Advice::NoReuse,
         }
     }
 }
 
-impl TryFrom<wasi::filesystem::DescriptorType> for types::Filetype {
+impl TryFrom<filesystem::DescriptorType> for types::Filetype {
     type Error = anyhow::Error;
 
-    fn try_from(ty: wasi::filesystem::DescriptorType) -> Result<Self, Self::Error> {
+    fn try_from(ty: filesystem::DescriptorType) -> Result<Self, Self::Error> {
         match ty {
-            wasi::filesystem::DescriptorType::RegularFile => Ok(types::Filetype::RegularFile),
-            wasi::filesystem::DescriptorType::Directory => Ok(types::Filetype::Directory),
-            wasi::filesystem::DescriptorType::BlockDevice => Ok(types::Filetype::BlockDevice),
-            wasi::filesystem::DescriptorType::CharacterDevice => {
-                Ok(types::Filetype::CharacterDevice)
-            }
+            filesystem::DescriptorType::RegularFile => Ok(types::Filetype::RegularFile),
+            filesystem::DescriptorType::Directory => Ok(types::Filetype::Directory),
+            filesystem::DescriptorType::BlockDevice => Ok(types::Filetype::BlockDevice),
+            filesystem::DescriptorType::CharacterDevice => Ok(types::Filetype::CharacterDevice),
             // preview1 never had a FIFO code.
-            wasi::filesystem::DescriptorType::Fifo => Ok(types::Filetype::Unknown),
+            filesystem::DescriptorType::Fifo => Ok(types::Filetype::Unknown),
             // TODO: Add a way to disginguish between FILETYPE_SOCKET_STREAM and
             // FILETYPE_SOCKET_DGRAM.
-            wasi::filesystem::DescriptorType::Socket => {
+            filesystem::DescriptorType::Socket => {
                 bail!("sockets are not currently supported")
             }
-            wasi::filesystem::DescriptorType::SymbolicLink => Ok(types::Filetype::SymbolicLink),
-            wasi::filesystem::DescriptorType::Unknown => Ok(types::Filetype::Unknown),
+            filesystem::DescriptorType::SymbolicLink => Ok(types::Filetype::SymbolicLink),
+            filesystem::DescriptorType::Unknown => Ok(types::Filetype::Unknown),
         }
     }
 }
 
-impl From<wasi::filesystem::ErrorCode> for types::Errno {
-    fn from(code: wasi::filesystem::ErrorCode) -> Self {
+impl From<filesystem::ErrorCode> for types::Errno {
+    fn from(code: filesystem::ErrorCode) -> Self {
         match code {
-            wasi::filesystem::ErrorCode::Access => types::Errno::Acces,
-            wasi::filesystem::ErrorCode::WouldBlock => types::Errno::Again,
-            wasi::filesystem::ErrorCode::Already => types::Errno::Already,
-            wasi::filesystem::ErrorCode::BadDescriptor => types::Errno::Badf,
-            wasi::filesystem::ErrorCode::Busy => types::Errno::Busy,
-            wasi::filesystem::ErrorCode::Deadlock => types::Errno::Deadlk,
-            wasi::filesystem::ErrorCode::Quota => types::Errno::Dquot,
-            wasi::filesystem::ErrorCode::Exist => types::Errno::Exist,
-            wasi::filesystem::ErrorCode::FileTooLarge => types::Errno::Fbig,
-            wasi::filesystem::ErrorCode::IllegalByteSequence => types::Errno::Ilseq,
-            wasi::filesystem::ErrorCode::InProgress => types::Errno::Inprogress,
-            wasi::filesystem::ErrorCode::Interrupted => types::Errno::Intr,
-            wasi::filesystem::ErrorCode::Invalid => types::Errno::Inval,
-            wasi::filesystem::ErrorCode::Io => types::Errno::Io,
-            wasi::filesystem::ErrorCode::IsDirectory => types::Errno::Isdir,
-            wasi::filesystem::ErrorCode::Loop => types::Errno::Loop,
-            wasi::filesystem::ErrorCode::TooManyLinks => types::Errno::Mlink,
-            wasi::filesystem::ErrorCode::MessageSize => types::Errno::Msgsize,
-            wasi::filesystem::ErrorCode::NameTooLong => types::Errno::Nametoolong,
-            wasi::filesystem::ErrorCode::NoDevice => types::Errno::Nodev,
-            wasi::filesystem::ErrorCode::NoEntry => types::Errno::Noent,
-            wasi::filesystem::ErrorCode::NoLock => types::Errno::Nolck,
-            wasi::filesystem::ErrorCode::InsufficientMemory => types::Errno::Nomem,
-            wasi::filesystem::ErrorCode::InsufficientSpace => types::Errno::Nospc,
-            wasi::filesystem::ErrorCode::Unsupported => types::Errno::Notsup,
-            wasi::filesystem::ErrorCode::NotDirectory => types::Errno::Notdir,
-            wasi::filesystem::ErrorCode::NotEmpty => types::Errno::Notempty,
-            wasi::filesystem::ErrorCode::NotRecoverable => types::Errno::Notrecoverable,
-            wasi::filesystem::ErrorCode::NoTty => types::Errno::Notty,
-            wasi::filesystem::ErrorCode::NoSuchDevice => types::Errno::Nxio,
-            wasi::filesystem::ErrorCode::Overflow => types::Errno::Overflow,
-            wasi::filesystem::ErrorCode::NotPermitted => types::Errno::Perm,
-            wasi::filesystem::ErrorCode::Pipe => types::Errno::Pipe,
-            wasi::filesystem::ErrorCode::ReadOnly => types::Errno::Rofs,
-            wasi::filesystem::ErrorCode::InvalidSeek => types::Errno::Spipe,
-            wasi::filesystem::ErrorCode::TextFileBusy => types::Errno::Txtbsy,
-            wasi::filesystem::ErrorCode::CrossDevice => types::Errno::Xdev,
+            filesystem::ErrorCode::Access => types::Errno::Acces,
+            filesystem::ErrorCode::WouldBlock => types::Errno::Again,
+            filesystem::ErrorCode::Already => types::Errno::Already,
+            filesystem::ErrorCode::BadDescriptor => types::Errno::Badf,
+            filesystem::ErrorCode::Busy => types::Errno::Busy,
+            filesystem::ErrorCode::Deadlock => types::Errno::Deadlk,
+            filesystem::ErrorCode::Quota => types::Errno::Dquot,
+            filesystem::ErrorCode::Exist => types::Errno::Exist,
+            filesystem::ErrorCode::FileTooLarge => types::Errno::Fbig,
+            filesystem::ErrorCode::IllegalByteSequence => types::Errno::Ilseq,
+            filesystem::ErrorCode::InProgress => types::Errno::Inprogress,
+            filesystem::ErrorCode::Interrupted => types::Errno::Intr,
+            filesystem::ErrorCode::Invalid => types::Errno::Inval,
+            filesystem::ErrorCode::Io => types::Errno::Io,
+            filesystem::ErrorCode::IsDirectory => types::Errno::Isdir,
+            filesystem::ErrorCode::Loop => types::Errno::Loop,
+            filesystem::ErrorCode::TooManyLinks => types::Errno::Mlink,
+            filesystem::ErrorCode::MessageSize => types::Errno::Msgsize,
+            filesystem::ErrorCode::NameTooLong => types::Errno::Nametoolong,
+            filesystem::ErrorCode::NoDevice => types::Errno::Nodev,
+            filesystem::ErrorCode::NoEntry => types::Errno::Noent,
+            filesystem::ErrorCode::NoLock => types::Errno::Nolck,
+            filesystem::ErrorCode::InsufficientMemory => types::Errno::Nomem,
+            filesystem::ErrorCode::InsufficientSpace => types::Errno::Nospc,
+            filesystem::ErrorCode::Unsupported => types::Errno::Notsup,
+            filesystem::ErrorCode::NotDirectory => types::Errno::Notdir,
+            filesystem::ErrorCode::NotEmpty => types::Errno::Notempty,
+            filesystem::ErrorCode::NotRecoverable => types::Errno::Notrecoverable,
+            filesystem::ErrorCode::NoTty => types::Errno::Notty,
+            filesystem::ErrorCode::NoSuchDevice => types::Errno::Nxio,
+            filesystem::ErrorCode::Overflow => types::Errno::Overflow,
+            filesystem::ErrorCode::NotPermitted => types::Errno::Perm,
+            filesystem::ErrorCode::Pipe => types::Errno::Pipe,
+            filesystem::ErrorCode::ReadOnly => types::Errno::Rofs,
+            filesystem::ErrorCode::InvalidSeek => types::Errno::Spipe,
+            filesystem::ErrorCode::TextFileBusy => types::Errno::Txtbsy,
+            filesystem::ErrorCode::CrossDevice => types::Errno::Xdev,
         }
     }
 }
 
-impl From<wasi::filesystem::ErrorCode> for types::Error {
-    fn from(code: wasi::filesystem::ErrorCode) -> Self {
+impl From<filesystem::ErrorCode> for types::Error {
+    fn from(code: filesystem::ErrorCode) -> Self {
         types::Errno::from(code).into()
     }
 }
 
-impl TryFrom<wasi::filesystem::Error> for types::Errno {
+impl TryFrom<filesystem::Error> for types::Errno {
     type Error = anyhow::Error;
 
-    fn try_from(err: wasi::filesystem::Error) -> Result<Self, Self::Error> {
+    fn try_from(err: filesystem::Error) -> Result<Self, Self::Error> {
         match err.downcast() {
             Ok(code) => Ok(code.into()),
             Err(e) => Err(e),
@@ -533,10 +514,10 @@ impl TryFrom<wasi::filesystem::Error> for types::Errno {
     }
 }
 
-impl TryFrom<wasi::filesystem::Error> for types::Error {
+impl TryFrom<filesystem::Error> for types::Error {
     type Error = anyhow::Error;
 
-    fn try_from(err: wasi::filesystem::Error) -> Result<Self, Self::Error> {
+    fn try_from(err: filesystem::Error) -> Result<Self, Self::Error> {
         match err.downcast() {
             Ok(code) => Ok(code.into()),
             Err(e) => Err(e),
@@ -642,15 +623,15 @@ fn first_non_empty_iovec<'a>(
 #[wiggle::async_trait]
 impl<
         T: WasiPreview1View
-            + wasi::environment::Host
-            + wasi::exit::Host
-            + wasi::filesystem::Host
-            + wasi::monotonic_clock::Host
-            + wasi::poll::Host
-            + wasi::preopens::Host
-            + wasi::random::Host
-            + wasi::streams::Host
-            + wasi::wall_clock::Host,
+            + wasi::cli_base::environment::Host
+            + wasi::cli_base::exit::Host
+            + wasi::cli_base::preopens::Host
+            + wasi::filesystem::filesystem::Host
+            + wasi::poll::poll::Host
+            + wasi::random::random::Host
+            + wasi::io::streams::Host
+            + wasi::clocks::monotonic_clock::Host
+            + wasi::clocks::wall_clock::Host,
     > wasi_snapshot_preview1::WasiSnapshotPreview1 for T
 {
     #[instrument(skip(self))]
@@ -756,12 +737,12 @@ impl<
         id: types::Clockid,
     ) -> Result<types::Timestamp, types::Error> {
         let res = match id {
-            types::Clockid::Realtime => wasi::wall_clock::Host::resolution(self)
+            types::Clockid::Realtime => wall_clock::Host::resolution(self)
                 .await
                 .context("failed to call `wall_clock::resolution`")
                 .map_err(types::Error::trap)?
                 .try_into()?,
-            types::Clockid::Monotonic => wasi::monotonic_clock::Host::resolution(self)
+            types::Clockid::Monotonic => monotonic_clock::Host::resolution(self)
                 .await
                 .context("failed to call `monotonic_clock::resolution`")
                 .map_err(types::Error::trap)?,
@@ -779,12 +760,12 @@ impl<
         _precision: types::Timestamp,
     ) -> Result<types::Timestamp, types::Error> {
         let now = match id {
-            types::Clockid::Realtime => wasi::wall_clock::Host::now(self)
+            types::Clockid::Realtime => wall_clock::Host::now(self)
                 .await
                 .context("failed to call `wall_clock::now`")
                 .map_err(types::Error::trap)?
                 .try_into()?,
-            types::Clockid::Monotonic => wasi::monotonic_clock::Host::now(self)
+            types::Clockid::Monotonic => monotonic_clock::Host::now(self)
                 .await
                 .context("failed to call `monotonic_clock::now`")
                 .map_err(types::Error::trap)?,
@@ -918,19 +899,19 @@ impl<
             .map_err(types::Error::trap)?;
         let mut fs_flags = types::Fdflags::empty();
         let mut fs_rights_base = types::Rights::all();
-        if !flags.contains(wasi::filesystem::DescriptorFlags::READ) {
+        if !flags.contains(filesystem::DescriptorFlags::READ) {
             fs_rights_base &= !types::Rights::FD_READ;
         }
-        if !flags.contains(wasi::filesystem::DescriptorFlags::WRITE) {
+        if !flags.contains(filesystem::DescriptorFlags::WRITE) {
             fs_rights_base &= !types::Rights::FD_WRITE;
         }
-        if flags.contains(wasi::filesystem::DescriptorFlags::DATA_INTEGRITY_SYNC) {
+        if flags.contains(filesystem::DescriptorFlags::DATA_INTEGRITY_SYNC) {
             fs_flags |= types::Fdflags::DSYNC;
         }
-        if flags.contains(wasi::filesystem::DescriptorFlags::REQUESTED_WRITE_SYNC) {
+        if flags.contains(filesystem::DescriptorFlags::REQUESTED_WRITE_SYNC) {
             fs_flags |= types::Fdflags::RSYNC;
         }
-        if flags.contains(wasi::filesystem::DescriptorFlags::FILE_INTEGRITY_SYNC) {
+        if flags.contains(filesystem::DescriptorFlags::FILE_INTEGRITY_SYNC) {
             fs_flags |= types::Fdflags::SYNC;
         }
         if append {
@@ -1002,7 +983,7 @@ impl<
                 })
             }
             Descriptor::PreopenDirectory((fd, _)) | Descriptor::File(File { fd, .. }) => {
-                let wasi::filesystem::DescriptorStat {
+                let filesystem::DescriptorStat {
                     device: dev,
                     inode: ino,
                     type_,
@@ -1109,7 +1090,7 @@ impl<
                 let (read, end) = if blocking {
                     self.blocking_read(stream, max)
                 } else {
-                    wasi::streams::Host::read(self, stream, max)
+                    streams::Host::read(self, stream, max)
                 }
                 .await
                 .map_err(|_| types::Errno::Io)?;
@@ -1124,13 +1105,10 @@ impl<
                 let Some(buf) = first_non_empty_iovec(iovs)? else {
                     return Ok(0)
                 };
-                let (read, end) = wasi::streams::Host::read(
-                    self,
-                    stream,
-                    buf.len().try_into().unwrap_or(u64::MAX),
-                )
-                .await
-                .map_err(|_| types::Errno::Io)?;
+                let (read, end) =
+                    streams::Host::read(self, stream, buf.len().try_into().unwrap_or(u64::MAX))
+                        .await
+                        .map_err(|_| types::Errno::Io)?;
                 (buf, read, end)
             }
             _ => return Err(types::Errno::Badf.into()),
@@ -1172,7 +1150,7 @@ impl<
                 let (read, end) = if blocking {
                     self.blocking_read(stream, max)
                 } else {
-                    wasi::streams::Host::read(self, stream, max)
+                    streams::Host::read(self, stream, max)
                 }
                 .await
                 .map_err(|_| types::Errno::Io)?;
@@ -1235,7 +1213,7 @@ impl<
                 let n = if blocking {
                     self.blocking_write(stream, buf)
                 } else {
-                    wasi::streams::Host::write(self, stream, buf)
+                    streams::Host::write(self, stream, buf)
                 }
                 .await
                 .map_err(|_| types::Errno::Io)?;
@@ -1249,7 +1227,7 @@ impl<
                 let Some(buf) = first_non_empty_ciovec(ciovs)? else {
                     return Ok(0)
                 };
-                wasi::streams::Host::write(self, stream, buf)
+                streams::Host::write(self, stream, buf)
                     .await
                     .map_err(|_| types::Errno::Io)?
             }
@@ -1283,7 +1261,7 @@ impl<
                 if blocking {
                     self.blocking_write(stream, buf)
                 } else {
-                    wasi::streams::Host::write(self, stream, buf)
+                    streams::Host::write(self, stream, buf)
                 }
                 .await
                 .map_err(|_| types::Errno::Io)?
@@ -1359,12 +1337,11 @@ impl<
                 .checked_add_signed(offset)
                 .ok_or(types::Errno::Inval)?,
             types::Whence::End => {
-                let wasi::filesystem::DescriptorStat { size, .. } =
-                    self.stat(fd).await.map_err(|e| {
-                        e.try_into()
-                            .context("failed to call `stat`")
-                            .unwrap_or_else(types::Error::trap)
-                    })?;
+                let filesystem::DescriptorStat { size, .. } = self.stat(fd).await.map_err(|e| {
+                    e.try_into()
+                        .context("failed to call `stat`")
+                        .unwrap_or_else(types::Error::trap)
+                })?;
                 size.checked_add_signed(offset).ok_or(types::Errno::Inval)?
             }
             _ => return Err(types::Errno::Inval.into()),
@@ -1411,7 +1388,7 @@ impl<
                 .context("failed to call `read-directory`")
                 .unwrap_or_else(types::Error::trap)
         })?;
-        let wasi::filesystem::DescriptorStat {
+        let filesystem::DescriptorStat {
             inode: fd_inode, ..
         } = self.stat(fd).await.map_err(|e| {
             e.try_into()
@@ -1450,12 +1427,11 @@ impl<
             .into_iter()
             .zip(3u64..)
             .map(|(entry, d_next)| {
-                let wasi::filesystem::DirectoryEntry { inode, type_, name } =
-                    entry.map_err(|e| {
-                        e.try_into()
-                            .context("failed to inspect `read-directory` entry")
-                            .unwrap_or_else(types::Error::trap)
-                    })?;
+                let filesystem::DirectoryEntry { inode, type_, name } = entry.map_err(|e| {
+                    e.try_into()
+                        .context("failed to inspect `read-directory` entry")
+                        .unwrap_or_else(types::Error::trap)
+                })?;
                 let d_type = type_.try_into().map_err(types::Error::trap)?;
                 let d_namlen: u32 = name.len().try_into().map_err(|_| types::Errno::Overflow)?;
                 Ok((
@@ -1534,7 +1510,7 @@ impl<
     ) -> Result<types::Filestat, types::Error> {
         let dirfd = self.get_dir_fd(dirfd).await?;
         let path = read_string(path)?;
-        let wasi::filesystem::DescriptorStat {
+        let filesystem::DescriptorStat {
             device: dev,
             inode: ino,
             type_,
@@ -1637,21 +1613,21 @@ impl<
     ) -> Result<types::Fd, types::Error> {
         let path = read_string(path)?;
 
-        let mut flags = wasi::filesystem::DescriptorFlags::empty();
+        let mut flags = filesystem::DescriptorFlags::empty();
         if fs_rights_base.contains(types::Rights::FD_READ) {
-            flags |= wasi::filesystem::DescriptorFlags::READ;
+            flags |= filesystem::DescriptorFlags::READ;
         }
         if fs_rights_base.contains(types::Rights::FD_WRITE) {
-            flags |= wasi::filesystem::DescriptorFlags::WRITE;
+            flags |= filesystem::DescriptorFlags::WRITE;
         }
         if fdflags.contains(types::Fdflags::SYNC) {
-            flags |= wasi::filesystem::DescriptorFlags::FILE_INTEGRITY_SYNC;
+            flags |= filesystem::DescriptorFlags::FILE_INTEGRITY_SYNC;
         }
         if fdflags.contains(types::Fdflags::DSYNC) {
-            flags |= wasi::filesystem::DescriptorFlags::DATA_INTEGRITY_SYNC;
+            flags |= filesystem::DescriptorFlags::DATA_INTEGRITY_SYNC;
         }
         if fdflags.contains(types::Fdflags::RSYNC) {
-            flags |= wasi::filesystem::DescriptorFlags::REQUESTED_WRITE_SYNC;
+            flags |= filesystem::DescriptorFlags::REQUESTED_WRITE_SYNC;
         }
 
         let desc = self.transact().await?.get_descriptor(dirfd)?.clone();
@@ -1671,7 +1647,7 @@ impl<
                 path,
                 oflags.into(),
                 flags,
-                wasi::filesystem::Modes::READABLE | wasi::filesystem::Modes::WRITABLE,
+                filesystem::Modes::READABLE | filesystem::Modes::WRITABLE,
             )
             .await
             .map_err(|e| {
diff --git a/crates/wasi/src/preview2/preview2/clocks.rs b/crates/wasi/src/preview2/preview2/clocks.rs
index d704c646d..75d292751 100644
--- a/crates/wasi/src/preview2/preview2/clocks.rs
+++ b/crates/wasi/src/preview2/preview2/clocks.rs
@@ -2,10 +2,10 @@
 
 use crate::preview2::preview2::poll::PollableEntry;
 use crate::preview2::wasi::{
-    monotonic_clock::{self, Instant},
-    poll::Pollable,
-    timezone::{self, Timezone, TimezoneDisplay},
-    wall_clock::{self, Datetime},
+    clocks::monotonic_clock::{self, Instant},
+    clocks::timezone::{self, Timezone, TimezoneDisplay},
+    clocks::wall_clock::{self, Datetime},
+    poll::poll::Pollable,
 };
 use crate::preview2::WasiView;
 use cap_std::time::SystemTime;
diff --git a/crates/wasi/src/preview2/preview2/env.rs b/crates/wasi/src/preview2/preview2/env.rs
index 580a126e2..b4288fc37 100644
--- a/crates/wasi/src/preview2/preview2/env.rs
+++ b/crates/wasi/src/preview2/preview2/env.rs
@@ -1,7 +1,14 @@
-use crate::preview2::{wasi, WasiView};
+use crate::preview2::wasi::cli_base::environment;
+use crate::preview2::wasi::cli_base::preopens;
+use crate::preview2::wasi::cli_base::stderr;
+use crate::preview2::wasi::cli_base::stdin;
+use crate::preview2::wasi::cli_base::stdout;
+use crate::preview2::wasi::filesystem::filesystem;
+use crate::preview2::wasi::io::streams;
+use crate::preview2::WasiView;
 
 #[async_trait::async_trait]
-impl<T: WasiView> wasi::environment::Host for T {
+impl<T: WasiView> environment::Host for T {
     async fn get_environment(&mut self) -> anyhow::Result<Vec<(String, String)>> {
         Ok(self.ctx().env.clone())
     }
@@ -11,31 +18,31 @@ impl<T: WasiView> wasi::environment::Host for T {
 }
 
 #[async_trait::async_trait]
-impl<T: WasiView> wasi::preopens::Host for T {
+impl<T: WasiView> preopens::Host for T {
     async fn get_directories(
         &mut self,
-    ) -> Result<Vec<(wasi::filesystem::Descriptor, String)>, anyhow::Error> {
+    ) -> Result<Vec<(filesystem::Descriptor, String)>, anyhow::Error> {
         Ok(self.ctx().preopens.clone())
     }
 }
 
 #[async_trait::async_trait]
-impl<T: WasiView> wasi::stdin::Host for T {
-    async fn get_stdin(&mut self) -> Result<wasi::streams::InputStream, anyhow::Error> {
+impl<T: WasiView> stdin::Host for T {
+    async fn get_stdin(&mut self) -> Result<streams::InputStream, anyhow::Error> {
         Ok(self.ctx().stdin)
     }
 }
 
 #[async_trait::async_trait]
-impl<T: WasiView> wasi::stdout::Host for T {
-    async fn get_stdout(&mut self) -> Result<wasi::streams::OutputStream, anyhow::Error> {
+impl<T: WasiView> stdout::Host for T {
+    async fn get_stdout(&mut self) -> Result<streams::OutputStream, anyhow::Error> {
         Ok(self.ctx().stdout)
     }
 }
 
 #[async_trait::async_trait]
-impl<T: WasiView> wasi::stderr::Host for T {
-    async fn get_stderr(&mut self) -> Result<wasi::streams::OutputStream, anyhow::Error> {
+impl<T: WasiView> stderr::Host for T {
+    async fn get_stderr(&mut self) -> Result<streams::OutputStream, anyhow::Error> {
         Ok(self.ctx().stderr)
     }
 }
diff --git a/crates/wasi/src/preview2/preview2/exit.rs b/crates/wasi/src/preview2/preview2/exit.rs
index 164e142ea..45754d594 100644
--- a/crates/wasi/src/preview2/preview2/exit.rs
+++ b/crates/wasi/src/preview2/preview2/exit.rs
@@ -1,4 +1,4 @@
-use crate::preview2::{wasi::exit, I32Exit, WasiView};
+use crate::preview2::{wasi::cli_base::exit, I32Exit, WasiView};
 
 #[async_trait::async_trait]
 impl<T: WasiView> exit::Host for T {
diff --git a/crates/wasi/src/preview2/preview2/filesystem.rs b/crates/wasi/src/preview2/preview2/filesystem.rs
index bd542ca4c..73c572314 100644
--- a/crates/wasi/src/preview2/preview2/filesystem.rs
+++ b/crates/wasi/src/preview2/preview2/filesystem.rs
@@ -1,29 +1,32 @@
 use crate::preview2::filesystem::{Dir, File, TableFsExt};
 use crate::preview2::stream::TableStreamExt;
-use crate::preview2::{wasi, DirPerms, FilePerms, Table, TableError, WasiView};
+use crate::preview2::wasi::clocks::wall_clock;
+use crate::preview2::wasi::filesystem::filesystem;
+use crate::preview2::wasi::io::streams;
+use crate::preview2::{DirPerms, FilePerms, Table, TableError, WasiView};
 
-use wasi::filesystem::ErrorCode;
+use filesystem::ErrorCode;
 
-impl From<TableError> for wasi::filesystem::Error {
-    fn from(error: TableError) -> wasi::filesystem::Error {
+impl From<TableError> for filesystem::Error {
+    fn from(error: TableError) -> filesystem::Error {
         match error {
-            TableError::Full => wasi::filesystem::Error::trap(anyhow::anyhow!(error)),
+            TableError::Full => filesystem::Error::trap(anyhow::anyhow!(error)),
             TableError::NotPresent | TableError::WrongType => ErrorCode::BadDescriptor.into(),
         }
     }
 }
 
 #[async_trait::async_trait]
-impl<T: WasiView> wasi::filesystem::Host for T {
+impl<T: WasiView> filesystem::Host for T {
     async fn advise(
         &mut self,
-        fd: wasi::filesystem::Descriptor,
-        offset: wasi::filesystem::Filesize,
-        len: wasi::filesystem::Filesize,
-        advice: wasi::filesystem::Advice,
-    ) -> Result<(), wasi::filesystem::Error> {
+        fd: filesystem::Descriptor,
+        offset: filesystem::Filesize,
+        len: filesystem::Filesize,
+        advice: filesystem::Advice,
+    ) -> Result<(), filesystem::Error> {
+        use filesystem::Advice;
         use system_interface::fs::{Advice as A, FileIoExt};
-        use wasi::filesystem::Advice;
 
         let advice = match advice {
             Advice::Normal => A::Normal,
@@ -39,10 +42,7 @@ impl<T: WasiView> wasi::filesystem::Host for T {
         Ok(())
     }
 
-    async fn sync_data(
-        &mut self,
-        fd: wasi::filesystem::Descriptor,
-    ) -> Result<(), wasi::filesystem::Error> {
+    async fn sync_data(&mut self, fd: filesystem::Descriptor) -> Result<(), filesystem::Error> {
         let table = self.table();
         if table.is_file(fd) {
             match table.get_file(fd)?.file.sync_data() {
@@ -72,11 +72,11 @@ impl<T: WasiView> wasi::filesystem::Host for T {
 
     async fn get_flags(
         &mut self,
-        fd: wasi::filesystem::Descriptor,
-    ) -> Result<wasi::filesystem::DescriptorFlags, wasi::filesystem::Error> {
+        fd: filesystem::Descriptor,
+    ) -> Result<filesystem::DescriptorFlags, filesystem::Error> {
         use cap_std::io_lifetimes::AsFilelike;
+        use filesystem::DescriptorFlags;
         use system_interface::fs::{FdFlags, GetSetFdFlags};
-        use wasi::filesystem::DescriptorFlags;
 
         fn get_from_fdflags(f: impl AsFilelike) -> std::io::Result<DescriptorFlags> {
             let flags = f.as_filelike().get_fd_flags()?;
@@ -121,15 +121,15 @@ impl<T: WasiView> wasi::filesystem::Host for T {
 
     async fn get_type(
         &mut self,
-        fd: wasi::filesystem::Descriptor,
-    ) -> Result<wasi::filesystem::DescriptorType, wasi::filesystem::Error> {
+        fd: filesystem::Descriptor,
+    ) -> Result<filesystem::DescriptorType, filesystem::Error> {
         let table = self.table();
 
         if table.is_file(fd) {
             let meta = table.get_file(fd)?.file.metadata()?;
             Ok(descriptortype_from(meta.file_type()))
         } else if table.is_dir(fd) {
-            Ok(wasi::filesystem::DescriptorType::Directory)
+            Ok(filesystem::DescriptorType::Directory)
         } else {
             Err(ErrorCode::BadDescriptor.into())
         }
@@ -137,9 +137,9 @@ impl<T: WasiView> wasi::filesystem::Host for T {
 
     async fn set_size(
         &mut self,
-        fd: wasi::filesystem::Descriptor,
-        size: wasi::filesystem::Filesize,
-    ) -> Result<(), wasi::filesystem::Error> {
+        fd: filesystem::Descriptor,
+        size: filesystem::Filesize,
+    ) -> Result<(), filesystem::Error> {
         let f = self.table().get_file(fd)?;
         if !f.perms.contains(FilePerms::WRITE) {
             Err(ErrorCode::NotPermitted)?;
@@ -150,10 +150,10 @@ impl<T: WasiView> wasi::filesystem::Host for T {
 
     async fn set_times(
         &mut self,
-        fd: wasi::filesystem::Descriptor,
-        atim: wasi::filesystem::NewTimestamp,
-        mtim: wasi::filesystem::NewTimestamp,
-    ) -> Result<(), wasi::filesystem::Error> {
+        fd: filesystem::Descriptor,
+        atim: filesystem::NewTimestamp,
+        mtim: filesystem::NewTimestamp,
+    ) -> Result<(), filesystem::Error> {
         use fs_set_times::SetTimes;
 
         let table = self.table();
@@ -182,10 +182,10 @@ impl<T: WasiView> wasi::filesystem::Host for T {
 
     async fn read(
         &mut self,
-        fd: wasi::filesystem::Descriptor,
-        len: wasi::filesystem::Filesize,
-        offset: wasi::filesystem::Filesize,
-    ) -> Result<(Vec<u8>, bool), wasi::filesystem::Error> {
+        fd: filesystem::Descriptor,
+        len: filesystem::Filesize,
+        offset: filesystem::Filesize,
+    ) -> Result<(Vec<u8>, bool), filesystem::Error> {
         use std::io::IoSliceMut;
         use system_interface::fs::FileIoExt;
 
@@ -213,10 +213,10 @@ impl<T: WasiView> wasi::filesystem::Host for T {
 
     async fn write(
         &mut self,
-        fd: wasi::filesystem::Descriptor,
+        fd: filesystem::Descriptor,
         buf: Vec<u8>,
-        offset: wasi::filesystem::Filesize,
-    ) -> Result<wasi::filesystem::Filesize, wasi::filesystem::Error> {
+        offset: filesystem::Filesize,
+    ) -> Result<filesystem::Filesize, filesystem::Error> {
         use std::io::IoSlice;
         use system_interface::fs::FileIoExt;
 
@@ -228,13 +228,13 @@ impl<T: WasiView> wasi::filesystem::Host for T {
 
         let bytes_written = f.file.write_vectored_at(&[IoSlice::new(&buf)], offset)?;
 
-        Ok(wasi::filesystem::Filesize::try_from(bytes_written).expect("usize fits in Filesize"))
+        Ok(filesystem::Filesize::try_from(bytes_written).expect("usize fits in Filesize"))
     }
 
     async fn read_directory(
         &mut self,
-        fd: wasi::filesystem::Descriptor,
-    ) -> Result<wasi::filesystem::DirectoryEntryStream, wasi::filesystem::Error> {
+        fd: filesystem::Descriptor,
+    ) -> Result<filesystem::DirectoryEntryStream, filesystem::Error> {
         use cap_fs_ext::{DirEntryExt, MetadataExt};
 
         let table = self.table_mut();
@@ -262,7 +262,7 @@ impl<T: WasiView> wasi::filesystem::Host for T {
                 .file_name()
                 .into_string()
                 .map_err(|_| ReaddirError::IllegalSequence)?;
-            Ok(wasi::filesystem::DirectoryEntry { inode, type_, name })
+            Ok(filesystem::DirectoryEntry { inode, type_, name })
         });
         // On windows, filter out files like `C:\DumpStack.log.tmp` which we
         // can't get full metadata for.
@@ -280,7 +280,7 @@ impl<T: WasiView> wasi::filesystem::Host for T {
         });
         let entries = entries.map(|r| match r {
             Ok(r) => Ok(r),
-            Err(ReaddirError::Io(e)) => Err(wasi::filesystem::Error::from(e)),
+            Err(ReaddirError::Io(e)) => Err(filesystem::Error::from(e)),
             Err(ReaddirError::IllegalSequence) => Err(ErrorCode::IllegalByteSequence.into()),
         });
         Ok(table.push_readdir(ReaddirIterator::new(entries))?)
@@ -288,8 +288,8 @@ impl<T: WasiView> wasi::filesystem::Host for T {
 
     async fn read_directory_entry(
         &mut self,
-        stream: wasi::filesystem::DirectoryEntryStream,
-    ) -> Result<Option<wasi::filesystem::DirectoryEntry>, wasi::filesystem::Error> {
+        stream: filesystem::DirectoryEntryStream,
+    ) -> Result<Option<filesystem::DirectoryEntry>, filesystem::Error> {
         let table = self.table();
         let readdir = table.get_readdir(stream)?;
         readdir.next()
@@ -297,16 +297,13 @@ impl<T: WasiView> wasi::filesystem::Host for T {
 
     async fn drop_directory_entry_stream(
         &mut self,
-        stream: wasi::filesystem::DirectoryEntryStream,
+        stream: filesystem::DirectoryEntryStream,
     ) -> anyhow::Result<()> {
         self.table_mut().delete_readdir(stream)?;
         Ok(())
     }
 
-    async fn sync(
-        &mut self,
-        fd: wasi::filesystem::Descriptor,
-    ) -> Result<(), wasi::filesystem::Error> {
+    async fn sync(&mut self, fd: filesystem::Descriptor) -> Result<(), filesystem::Error> {
         let table = self.table();
         if table.is_file(fd) {
             match table.get_file(fd)?.file.sync_all() {
@@ -336,9 +333,9 @@ impl<T: WasiView> wasi::filesystem::Host for T {
 
     async fn create_directory_at(
         &mut self,
-        fd: wasi::filesystem::Descriptor,
+        fd: filesystem::Descriptor,
         path: String,
-    ) -> Result<(), wasi::filesystem::Error> {
+    ) -> Result<(), filesystem::Error> {
         let table = self.table();
         let d = table.get_dir(fd)?;
         if !d.perms.contains(DirPerms::MUTATE) {
@@ -350,8 +347,8 @@ impl<T: WasiView> wasi::filesystem::Host for T {
 
     async fn stat(
         &mut self,
-        fd: wasi::filesystem::Descriptor,
-    ) -> Result<wasi::filesystem::DescriptorStat, wasi::filesystem::Error> {
+        fd: filesystem::Descriptor,
+    ) -> Result<filesystem::DescriptorStat, filesystem::Error> {
         let table = self.table();
         if table.is_file(fd) {
             let f = table.get_file(fd)?;
@@ -374,10 +371,10 @@ impl<T: WasiView> wasi::filesystem::Host for T {
 
     async fn stat_at(
         &mut self,
-        fd: wasi::filesystem::Descriptor,
-        path_flags: wasi::filesystem::PathFlags,
+        fd: filesystem::Descriptor,
+        path_flags: filesystem::PathFlags,
         path: String,
-    ) -> Result<wasi::filesystem::DescriptorStat, wasi::filesystem::Error> {
+    ) -> Result<filesystem::DescriptorStat, filesystem::Error> {
         let table = self.table();
         let d = table.get_dir(fd)?;
         if !d.perms.contains(DirPerms::READ) {
@@ -394,12 +391,12 @@ impl<T: WasiView> wasi::filesystem::Host for T {
 
     async fn set_times_at(
         &mut self,
-        fd: wasi::filesystem::Descriptor,
-        path_flags: wasi::filesystem::PathFlags,
+        fd: filesystem::Descriptor,
+        path_flags: filesystem::PathFlags,
         path: String,
-        atim: wasi::filesystem::NewTimestamp,
-        mtim: wasi::filesystem::NewTimestamp,
-    ) -> Result<(), wasi::filesystem::Error> {
+        atim: filesystem::NewTimestamp,
+        mtim: filesystem::NewTimestamp,
+    ) -> Result<(), filesystem::Error> {
         use cap_fs_ext::DirExt;
 
         let table = self.table();
@@ -427,13 +424,13 @@ impl<T: WasiView> wasi::filesystem::Host for T {
 
     async fn link_at(
         &mut self,
-        fd: wasi::filesystem::Descriptor,
+        fd: filesystem::Descriptor,
         // TODO delete the path flags from this function
-        old_path_flags: wasi::filesystem::PathFlags,
+        old_path_flags: filesystem::PathFlags,
         old_path: String,
-        new_descriptor: wasi::filesystem::Descriptor,
+        new_descriptor: filesystem::Descriptor,
         new_path: String,
-    ) -> Result<(), wasi::filesystem::Error> {
+    ) -> Result<(), filesystem::Error> {
         let table = self.table();
         let old_dir = table.get_dir(fd)?;
         if !old_dir.perms.contains(DirPerms::MUTATE) {
@@ -452,18 +449,18 @@ impl<T: WasiView> wasi::filesystem::Host for T {
 
     async fn open_at(
         &mut self,
-        fd: wasi::filesystem::Descriptor,
-        path_flags: wasi::filesystem::PathFlags,
+        fd: filesystem::Descriptor,
+        path_flags: filesystem::PathFlags,
         path: String,
-        oflags: wasi::filesystem::OpenFlags,
-        flags: wasi::filesystem::DescriptorFlags,
+        oflags: filesystem::OpenFlags,
+        flags: filesystem::DescriptorFlags,
         // TODO: These are the permissions to use when creating a new file.
         // Not implemented yet.
-        _mode: wasi::filesystem::Modes,
-    ) -> Result<wasi::filesystem::Descriptor, wasi::filesystem::Error> {
+        _mode: filesystem::Modes,
+    ) -> Result<filesystem::Descriptor, filesystem::Error> {
         use cap_fs_ext::{FollowSymlinks, OpenOptionsFollowExt, OpenOptionsMaybeDirExt};
+        use filesystem::{DescriptorFlags, OpenFlags};
         use system_interface::fs::{FdFlags, GetSetFdFlags};
-        use wasi::filesystem::{DescriptorFlags, OpenFlags};
 
         let table = self.table_mut();
         if table.is_file(fd) {
@@ -548,7 +545,7 @@ impl<T: WasiView> wasi::filesystem::Host for T {
         }
     }
 
-    async fn drop_descriptor(&mut self, fd: wasi::filesystem::Descriptor) -> anyhow::Result<()> {
+    async fn drop_descriptor(&mut self, fd: filesystem::Descriptor) -> anyhow::Result<()> {
         let table = self.table_mut();
         if table.delete_file(fd).is_err() {
             table.delete_dir(fd)?;
@@ -558,9 +555,9 @@ impl<T: WasiView> wasi::filesystem::Host for T {
 
     async fn readlink_at(
         &mut self,
-        fd: wasi::filesystem::Descriptor,
+        fd: filesystem::Descriptor,
         path: String,
-    ) -> Result<String, wasi::filesystem::Error> {
+    ) -> Result<String, filesystem::Error> {
         let table = self.table();
         let d = table.get_dir(fd)?;
         if !d.perms.contains(DirPerms::READ) {
@@ -575,9 +572,9 @@ impl<T: WasiView> wasi::filesystem::Host for T {
 
     async fn remove_directory_at(
         &mut self,
-        fd: wasi::filesystem::Descriptor,
+        fd: filesystem::Descriptor,
         path: String,
-    ) -> Result<(), wasi::filesystem::Error> {
+    ) -> Result<(), filesystem::Error> {
         let table = self.table();
         let d = table.get_dir(fd)?;
         if !d.perms.contains(DirPerms::MUTATE) {
@@ -588,11 +585,11 @@ impl<T: WasiView> wasi::filesystem::Host for T {
 
     async fn rename_at(
         &mut self,
-        fd: wasi::filesystem::Descriptor,
+        fd: filesystem::Descriptor,
         old_path: String,
-        new_fd: wasi::filesystem::Descriptor,
+        new_fd: filesystem::Descriptor,
         new_path: String,
-    ) -> Result<(), wasi::filesystem::Error> {
+    ) -> Result<(), filesystem::Error> {
         let table = self.table();
         let old_dir = table.get_dir(fd)?;
         if !old_dir.perms.contains(DirPerms::MUTATE) {
@@ -608,10 +605,10 @@ impl<T: WasiView> wasi::filesystem::Host for T {
 
     async fn symlink_at(
         &mut self,
-        fd: wasi::filesystem::Descriptor,
+        fd: filesystem::Descriptor,
         src_path: String,
         dest_path: String,
-    ) -> Result<(), wasi::filesystem::Error> {
+    ) -> Result<(), filesystem::Error> {
         // On windows, Dir.symlink is provided by DirExt
         #[cfg(windows)]
         use cap_fs_ext::DirExt;
@@ -627,9 +624,9 @@ impl<T: WasiView> wasi::filesystem::Host for T {
 
     async fn unlink_file_at(
         &mut self,
-        fd: wasi::filesystem::Descriptor,
+        fd: filesystem::Descriptor,
         path: String,
-    ) -> Result<(), wasi::filesystem::Error> {
+    ) -> Result<(), filesystem::Error> {
         use cap_fs_ext::DirExt;
 
         let table = self.table();
@@ -643,74 +640,68 @@ impl<T: WasiView> wasi::filesystem::Host for T {
 
     async fn access_at(
         &mut self,
-        _fd: wasi::filesystem::Descriptor,
-        _path_flags: wasi::filesystem::PathFlags,
+        _fd: filesystem::Descriptor,
+        _path_flags: filesystem::PathFlags,
         _path: String,
-        _access: wasi::filesystem::AccessType,
-    ) -> Result<(), wasi::filesystem::Error> {
+        _access: filesystem::AccessType,
+    ) -> Result<(), filesystem::Error> {
         todo!()
     }
 
     async fn change_file_permissions_at(
         &mut self,
-        _fd: wasi::filesystem::Descriptor,
-        _path_flags: wasi::filesystem::PathFlags,
+        _fd: filesystem::Descriptor,
+        _path_flags: filesystem::PathFlags,
         _path: String,
-        _mode: wasi::filesystem::Modes,
-    ) -> Result<(), wasi::filesystem::Error> {
+        _mode: filesystem::Modes,
+    ) -> Result<(), filesystem::Error> {
         todo!()
     }
 
     async fn change_directory_permissions_at(
         &mut self,
-        _fd: wasi::filesystem::Descriptor,
-        _path_flags: wasi::filesystem::PathFlags,
+        _fd: filesystem::Descriptor,
+        _path_flags: filesystem::PathFlags,
         _path: String,
-        _mode: wasi::filesystem::Modes,
-    ) -> Result<(), wasi::filesystem::Error> {
+        _mode: filesystem::Modes,
+    ) -> Result<(), filesystem::Error> {
         todo!()
     }
 
-    async fn lock_shared(
-        &mut self,
-        _fd: wasi::filesystem::Descriptor,
-    ) -> Result<(), wasi::filesystem::Error> {
+    async fn lock_shared(&mut self, _fd: filesystem::Descriptor) -> Result<(), filesystem::Error> {
         todo!()
     }
 
     async fn lock_exclusive(
         &mut self,
-        _fd: wasi::filesystem::Descriptor,
-    ) -> Result<(), wasi::filesystem::Error> {
+        _fd: filesystem::Descriptor,
+    ) -> Result<(), filesystem::Error> {
         todo!()
     }
 
     async fn try_lock_shared(
         &mut self,
-        _fd: wasi::filesystem::Descriptor,
-    ) -> Result<(), wasi::filesystem::Error> {
+        _fd: filesystem::Descriptor,
+    ) -> Result<(), filesystem::Error> {
         todo!()
     }
 
     async fn try_lock_exclusive(
         &mut self,
-        _fd: wasi::filesystem::Descriptor,
-    ) -> Result<(), wasi::filesystem::Error> {
+        _fd: filesystem::Descriptor,
+    ) -> Result<(), filesystem::Error> {
         todo!()
     }
 
-    async fn unlock(
-        &mut self,
-        _fd: wasi::filesystem::Descriptor,
-    ) -> Result<(), wasi::filesystem::Error> {
+    async fn unlock(&mut self, _fd: filesystem::Descriptor) -> Result<(), filesystem::Error> {
         todo!()
     }
 
     async fn read_via_stream(
         &mut self,
-        fd: wasi::filesystem::Descriptor,
-        offset: wasi::filesystem::Filesize,
-    ) -> anyhow::Result<wasi::streams::InputStream> {
+        fd: filesystem::Descriptor,
+        offset: filesystem::Filesize,
+    ) -> anyhow::Result<streams::InputStream> {
         // FIXME: this skips the perm check. We can't return a NotPermitted
         // error code here. Do we need to change the interface?
 
@@ -731,9 +722,9 @@ impl<T: WasiView> wasi::filesystem::Host for T {
 
     async fn write_via_stream(
         &mut self,
-        fd: wasi::filesystem::Descriptor,
-        offset: wasi::filesystem::Filesize,
-    ) -> anyhow::Result<wasi::streams::OutputStream> {
+        fd: filesystem::Descriptor,
+        offset: filesystem::Filesize,
+    ) -> anyhow::Result<streams::OutputStream> {
         // Trap if fd lookup fails:
         let f = self.table().get_file(fd)?;
 
@@ -751,8 +742,8 @@ impl<T: WasiView> wasi::filesystem::Host for T {
 
     async fn append_via_stream(
         &mut self,
-        fd: wasi::filesystem::Descriptor,
-    ) -> anyhow::Result<wasi::streams::OutputStream> {
+        fd: filesystem::Descriptor,
+    ) -> anyhow::Result<streams::OutputStream> {
         // Trap if fd lookup fails:
         let f = self.table().get_file(fd)?;
 
@@ -770,7 +761,7 @@ impl<T: WasiView> wasi::filesystem::Host for T {
 }
 
 #[cfg(unix)]
-fn from_raw_os_error(err: Option<i32>) -> Option<wasi::filesystem::Error> {
+fn from_raw_os_error(err: Option<i32>) -> Option<filesystem::Error> {
     use rustix::io::Errno as RustixErrno;
     if err.is_none() {
         return None;
@@ -810,7 +801,7 @@ fn from_raw_os_error(err: Option<i32>) -> Option<wasi::filesystem::Error> {
     })
 }
 #[cfg(windows)]
-fn from_raw_os_error(raw_os_error: Option<i32>) -> Option<wasi::filesystem::Error> {
+fn from_raw_os_error(raw_os_error: Option<i32>) -> Option<filesystem::Error> {
     use windows_sys::Win32::Foundation;
     Some(match raw_os_error.map(|code| code as u32) {
         Some(Foundation::ERROR_FILE_NOT_FOUND) => ErrorCode::NoEntry.into(),
@@ -839,8 +830,8 @@ fn from_raw_os_error(raw_os_error: Option<i32>) -> Option<wasi::filesystem::Erro
     })
 }
 
-impl From<std::io::Error> for wasi::filesystem::Error {
-    fn from(err: std::io::Error) -> wasi::filesystem::Error {
+impl From<std::io::Error> for filesystem::Error {
+    fn from(err: std::io::Error) -> filesystem::Error {
         match from_raw_os_error(err.raw_os_error()) {
             Some(errno) => errno,
             None => match err.kind() {
@@ -848,31 +839,29 @@ impl From<std::io::Error> for wasi::filesystem::Error {
                 std::io::ErrorKind::PermissionDenied => ErrorCode::NotPermitted.into(),
                 std::io::ErrorKind::AlreadyExists => ErrorCode::Exist.into(),
                 std::io::ErrorKind::InvalidInput => ErrorCode::Invalid.into(),
-                _ => {
-                    wasi::filesystem::Error::trap(anyhow::anyhow!(err).context("Unknown OS error"))
-                }
+                _ => filesystem::Error::trap(anyhow::anyhow!(err).context("Unknown OS error")),
             },
         }
     }
 }
 
-impl From<cap_rand::Error> for wasi::filesystem::Error {
-    fn from(err: cap_rand::Error) -> wasi::filesystem::Error {
+impl From<cap_rand::Error> for filesystem::Error {
+    fn from(err: cap_rand::Error) -> filesystem::Error {
         // I picked Error::Io as a 'reasonable default', FIXME dan is this ok?
         from_raw_os_error(err.raw_os_error())
-            .unwrap_or_else(|| wasi::filesystem::Error::from(ErrorCode::Io))
+            .unwrap_or_else(|| filesystem::Error::from(ErrorCode::Io))
     }
 }
 
-impl From<std::num::TryFromIntError> for wasi::filesystem::Error {
-    fn from(_err: std::num::TryFromIntError) -> wasi::filesystem::Error {
+impl From<std::num::TryFromIntError> for filesystem::Error {
+    fn from(_err: std::num::TryFromIntError) -> filesystem::Error {
         ErrorCode::Overflow.into()
     }
 }
 
-fn descriptortype_from(ft: cap_std::fs::FileType) -> wasi::filesystem::DescriptorType {
+fn descriptortype_from(ft: cap_std::fs::FileType) -> filesystem::DescriptorType {
     use cap_fs_ext::FileTypeExt;
-    use wasi::filesystem::DescriptorType;
+    use filesystem::DescriptorType;
     if ft.is_dir() {
         DescriptorType::Directory
     } else if ft.is_symlink() {
@@ -889,10 +878,10 @@ fn descriptortype_from(ft: cap_std::fs::FileType) -> wasi::filesystem::Descripto
 }
 
 fn systemtimespec_from(
-    t: wasi::filesystem::NewTimestamp,
-) -> Result<Option<fs_set_times::SystemTimeSpec>, wasi::filesystem::Error> {
+    t: filesystem::NewTimestamp,
+) -> Result<Option<fs_set_times::SystemTimeSpec>, filesystem::Error> {
+    use filesystem::NewTimestamp;
     use fs_set_times::SystemTimeSpec;
-    use wasi::filesystem::NewTimestamp;
     match t {
         NewTimestamp::NoChange => Ok(None),
         NewTimestamp::Now => Ok(Some(SystemTimeSpec::SymbolicNow)),
@@ -900,23 +889,21 @@ fn systemtimespec_from(
     }
 }
 
-fn systemtime_from(
-    t: wasi::wall_clock::Datetime,
-) -> Result<std::time::SystemTime, wasi::filesystem::Error> {
+fn systemtime_from(t: wall_clock::Datetime) -> Result<std::time::SystemTime, filesystem::Error> {
     use std::time::{Duration, SystemTime};
     SystemTime::UNIX_EPOCH
         .checked_add(Duration::new(t.seconds, t.nanoseconds))
         .ok_or_else(|| ErrorCode::Overflow.into())
 }
 
-fn datetime_from(t: std::time::SystemTime) -> wasi::wall_clock::Datetime {
+fn datetime_from(t: std::time::SystemTime) -> wall_clock::Datetime {
     // FIXME make this infallible or handle errors properly
-    wasi::wall_clock::Datetime::try_from(cap_std::time::SystemTime::from_std(t)).unwrap()
+    wall_clock::Datetime::try_from(cap_std::time::SystemTime::from_std(t)).unwrap()
 }
 
-fn descriptorstat_from(meta: cap_std::fs::Metadata) -> wasi::filesystem::DescriptorStat {
+fn descriptorstat_from(meta: cap_std::fs::Metadata) -> filesystem::DescriptorStat {
     use cap_fs_ext::MetadataExt;
-    wasi::filesystem::DescriptorStat {
+    filesystem::DescriptorStat {
         // FIXME didn't we agree that the wit could be changed to make the device and ino fields
         // optional?
         device: meta.dev(),
@@ -928,35 +915,35 @@ fn descriptorstat_from(meta: cap_std::fs::Metadata) -> wasi::filesystem::Descrip
         data_access_timestamp: meta
             .accessed()
             .map(|t| datetime_from(t.into_std()))
-            .unwrap_or(wasi::wall_clock::Datetime {
+            .unwrap_or(wall_clock::Datetime {
                 seconds: 0,
                 nanoseconds: 0,
             }),
         data_modification_timestamp: meta
             .modified()
             .map(|t| datetime_from(t.into_std()))
-            .unwrap_or(wasi::wall_clock::Datetime {
+            .unwrap_or(wall_clock::Datetime {
                 seconds: 0,
                 nanoseconds: 0,
             }),
         status_change_timestamp: meta
             .created()
             .map(|t| datetime_from(t.into_std()))
-            .unwrap_or(wasi::wall_clock::Datetime {
+            .unwrap_or(wall_clock::Datetime {
                 seconds: 0,
                 nanoseconds: 0,
             }),
     }
 }
 
-fn symlink_follow(path_flags: wasi::filesystem::PathFlags) -> bool {
-    path_flags.contains(wasi::filesystem::PathFlags::SYMLINK_FOLLOW)
+fn symlink_follow(path_flags: filesystem::PathFlags) -> bool {
+    path_flags.contains(filesystem::PathFlags::SYMLINK_FOLLOW)
 }
 
 pub(crate) struct ReaddirIterator(
     std::sync::Mutex<
         Box<
-            dyn Iterator<Item = Result<wasi::filesystem::DirectoryEntry, wasi::filesystem::Error>>
+            dyn Iterator<Item = Result<filesystem::DirectoryEntry, filesystem::Error>>
                 + Send
                 + 'static,
         >,
@@ -965,19 +952,17 @@ pub(crate) struct ReaddirIterator(
 
 impl ReaddirIterator {
     fn new(
-        i: impl Iterator<Item = Result<wasi::filesystem::DirectoryEntry, wasi::filesystem::Error>>
-            + Send
-            + 'static,
+        i: impl Iterator<Item = Result<filesystem::DirectoryEntry, filesystem::Error>> + Send + 'static,
     ) -> Self {
         ReaddirIterator(std::sync::Mutex::new(Box::new(i)))
     }
-    fn next(&self) -> Result<Option<wasi::filesystem::DirectoryEntry>, wasi::filesystem::Error> {
+    fn next(&self) -> Result<Option<filesystem::DirectoryEntry>, filesystem::Error> {
         self.0.lock().unwrap().next().transpose()
     }
 }
 
 impl IntoIterator for ReaddirIterator {
-    type Item = Result<wasi::filesystem::DirectoryEntry, wasi::filesystem::Error>;
+    type Item = Result<filesystem::DirectoryEntry, filesystem::Error>;
     type IntoIter = Box<dyn Iterator<Item = Self::Item>>;
 
     fn into_iter(self) -> Self::IntoIter {
diff --git a/crates/wasi/src/preview2/preview2/io.rs b/crates/wasi/src/preview2/preview2/io.rs
index 407ae2c54..4e9971f2d 100644
--- a/crates/wasi/src/preview2/preview2/io.rs
+++ b/crates/wasi/src/preview2/preview2/io.rs
@@ -1,8 +1,8 @@
 use crate::preview2::{
     preview2::poll::PollableEntry,
     stream::TableStreamExt,
-    wasi::poll::Pollable,
-    wasi::streams::{self, InputStream, OutputStream, StreamError},
+    wasi::io::streams::{self, InputStream, OutputStream, StreamError},
+    wasi::poll::poll::Pollable,
     TableError, WasiView,
 };
 use anyhow::anyhow;
diff --git a/crates/wasi/src/preview2/preview2/poll.rs b/crates/wasi/src/preview2/preview2/poll.rs
index 311c36ab1..d3b9380c7 100644
--- a/crates/wasi/src/preview2/preview2/poll.rs
+++ b/crates/wasi/src/preview2/preview2/poll.rs
@@ -1,9 +1,8 @@
 use crate::preview2::{
     stream::TableStreamExt,
-    wasi,
-    wasi::monotonic_clock::Instant,
-    wasi::poll::Pollable,
-    wasi::streams::{InputStream, OutputStream},
+    wasi::clocks::monotonic_clock::Instant,
+    wasi::io::streams::{InputStream, OutputStream},
+    wasi::poll::poll::{self, Pollable},
     WasiView,
 };
 
@@ -29,7 +28,7 @@ pub(crate) enum PollableEntry {
 // this PR.
 
 #[async_trait::async_trait]
-impl<T: WasiView> wasi::poll::Host for T {
+impl<T: WasiView> poll::Host for T {
     async fn drop_pollable(&mut self, pollable: Pollable) -> anyhow::Result<()> {
         self.table_mut().delete::<PollableEntry>(pollable)?;
         Ok(())
diff --git a/crates/wasi/src/preview2/preview2/random.rs b/crates/wasi/src/preview2/preview2/random.rs
index f94afed84..2cabe352b 100644
--- a/crates/wasi/src/preview2/preview2/random.rs
+++ b/crates/wasi/src/preview2/preview2/random.rs
@@ -1,9 +1,11 @@
+use crate::preview2::wasi::random::insecure;
+use crate::preview2::wasi::random::insecure_seed;
+use crate::preview2::wasi::random::random;
+use crate::preview2::WasiView;
 use cap_rand::{distributions::Standard, Rng};
 
-use crate::preview2::{wasi, WasiView};
-
 #[async_trait::async_trait]
-impl<T: WasiView> wasi::random::Host for T {
+impl<T: WasiView> random::Host for T {
     async fn get_random_bytes(&mut self, len: u64) -> anyhow::Result<Vec<u8>> {
         Ok((&mut self.ctx_mut().random)
             .sample_iter(Standard)
@@ -17,7 +19,7 @@ impl<T: WasiView> wasi::random::Host for T {
 }
 
 #[async_trait::async_trait]
-impl<T: WasiView> wasi::insecure_random::Host for T {
+impl<T: WasiView> insecure::Host for T {
     async fn get_insecure_random_bytes(&mut self, len: u64) -> anyhow::Result<Vec<u8>> {
         Ok((&mut self.ctx_mut().insecure_random)
             .sample_iter(Standard)
@@ -31,7 +33,7 @@ impl<T: WasiView> wasi::insecure_random::Host for T {
 }
 
 #[async_trait::async_trait]
-impl<T: WasiView> wasi::insecure_random_seed::Host for T {
+impl<T: WasiView> insecure_seed::Host for T {
     async fn insecure_seed(&mut self) -> anyhow::Result<(u64, u64)> {
         let seed: u128 = self.ctx_mut().insecure_random_seed;
         Ok((seed as u64, (seed >> 64) as u64))
diff --git a/crates/wasi/src/preview2/wasi/command.rs b/crates/wasi/src/preview2/wasi/command.rs
index 6bc26f20b..9dc472536 100644
--- a/crates/wasi/src/preview2/wasi/command.rs
+++ b/crates/wasi/src/preview2/wasi/command.rs
@@ -1,8 +1,7 @@
 use crate::preview2::WasiView;
 
 wasmtime::component::bindgen!({
-    path: "wit",
-    world: "command",
+    world: "wasi:preview/command",
     tracing: true,
     async: true,
     trappable_error_type: {
@@ -10,35 +9,35 @@ wasmtime::component::bindgen!({
         "streams"::"stream-error": Error,
     },
     with: {
-       "filesystem": crate::preview2::wasi::filesystem,
-       "monotonic_clock": crate::preview2::wasi::monotonic_clock,
-       "poll": crate::preview2::wasi::poll,
-       "streams": crate::preview2::wasi::streams,
-       "timezone": crate::preview2::wasi::timezone,
-       "wall_clock": crate::preview2::wasi::wall_clock,
-       "random": crate::preview2::wasi::random,
-       "environment": crate::preview2::wasi::environment,
-       "exit": crate::preview2::wasi::exit,
-       "preopens": crate::preview2::wasi::preopens,
-       "stdin": crate::preview2::wasi::stdin,
-       "stdout": crate::preview2::wasi::stdout,
-       "stderr": crate::preview2::wasi::stderr,
+       "wasi:filesystem/filesystem": crate::preview2::wasi::filesystem::filesystem,
+       "wasi:clocks/monotonic_clock": crate::preview2::wasi::clocks::monotonic_clock,
+       "wasi:poll/poll": crate::preview2::wasi::poll::poll,
+       "wasi:io/streams": crate::preview2::wasi::io::streams,
+       "wasi:clocks/timezone": crate::preview2::wasi::clocks::timezone,
+       "wasi:clocks/wall_clock": crate::preview2::wasi::clocks::wall_clock,
+       "wasi:random/random": crate::preview2::wasi::random::random,
+       "wasi:cli_base/environment": crate::preview2::wasi::cli_base::environment,
+       "wasi:cli_base/exit": crate::preview2::wasi::cli_base::exit,
+       "wasi:cli_base/preopens": crate::preview2::wasi::cli_base::preopens,
+       "wasi:cli_base/stdin": crate::preview2::wasi::cli_base::stdin,
+       "wasi:cli_base/stdout": crate::preview2::wasi::cli_base::stdout,
+       "wasi:cli_base/stderr": crate::preview2::wasi::cli_base::stderr,
     },
 });
 
 pub fn add_to_linker<T: WasiView>(l: &mut wasmtime::component::Linker<T>) -> anyhow::Result<()> {
-    crate::preview2::wasi::wall_clock::add_to_linker(l, |t| t)?;
-    crate::preview2::wasi::monotonic_clock::add_to_linker(l, |t| t)?;
-    crate::preview2::wasi::timezone::add_to_linker(l, |t| t)?;
-    crate::preview2::wasi::filesystem::add_to_linker(l, |t| t)?;
-    crate::preview2::wasi::poll::add_to_linker(l, |t| t)?;
-    crate::preview2::wasi::streams::add_to_linker(l, |t| t)?;
-    crate::preview2::wasi::random::add_to_linker(l, |t| t)?;
-    crate::preview2::wasi::exit::add_to_linker(l, |t| t)?;
-    crate::preview2::wasi::environment::add_to_linker(l, |t| t)?;
-    crate::preview2::wasi::preopens::add_to_linker(l, |t| t)?;
-    crate::preview2::wasi::stdin::add_to_linker(l, |t| t)?;
-    crate::preview2::wasi::stdout::add_to_linker(l, |t| t)?;
-    crate::preview2::wasi::stderr::add_to_linker(l, |t| t)?;
+    crate::preview2::wasi::clocks::wall_clock::add_to_linker(l, |t| t)?;
+    crate::preview2::wasi::clocks::monotonic_clock::add_to_linker(l, |t| t)?;
+    crate::preview2::wasi::clocks::timezone::add_to_linker(l, |t| t)?;
+    crate::preview2::wasi::filesystem::filesystem::add_to_linker(l, |t| t)?;
+    crate::preview2::wasi::poll::poll::add_to_linker(l, |t| t)?;
+    crate::preview2::wasi::io::streams::add_to_linker(l, |t| t)?;
+    crate::preview2::wasi::random::random::add_to_linker(l, |t| t)?;
+    crate::preview2::wasi::cli_base::exit::add_to_linker(l, |t| t)?;
+    crate::preview2::wasi::cli_base::environment::add_to_linker(l, |t| t)?;
+    crate::preview2::wasi::cli_base::preopens::add_to_linker(l, |t| t)?;
+    crate::preview2::wasi::cli_base::stdin::add_to_linker(l, |t| t)?;
+    crate::preview2::wasi::cli_base::stdout::add_to_linker(l, |t| t)?;
+    crate::preview2::wasi::cli_base::stderr::add_to_linker(l, |t| t)?;
     Ok(())
 }
diff --git a/crates/wasi/src/preview2/wasi/mod.rs b/crates/wasi/src/preview2/wasi/mod.rs
index 40aa9af2d..aa1a1708a 100644
--- a/crates/wasi/src/preview2/wasi/mod.rs
+++ b/crates/wasi/src/preview2/wasi/mod.rs
@@ -3,21 +3,21 @@ pub mod command;
 wasmtime::component::bindgen!({
     path: "wit",
     interfaces: "
-      import wall-clock: clocks.wall-clock
-      import monotonic-clock: clocks.monotonic-clock
-      import timezone: clocks.timezone
-      import filesystem: filesystem.filesystem
-      import random: random.random
-      import insecure-random: random.insecure
-      import insecure-random-seed: random.insecure-seed
-      import poll: poll.poll
-      import streams: io.streams
-      import environment: wasi-cli-base.environment
-      import preopens: wasi-cli-base.preopens
-      import stdin: wasi-cli-base.stdio.stdin
-      import stdout: wasi-cli-base.stdio.stdout
-      import stderr: wasi-cli-base.stdio.stderr
-      import exit: wasi-cli-base.exit
+      import wasi:clocks/wall-clock
+      import wasi:clocks/monotonic-clock
+      import wasi:clocks/timezone
+      import wasi:filesystem/filesystem
+      import wasi:random/random
+      import wasi:random/insecure
+      import wasi:random/insecure-seed
+      import wasi:poll/poll
+      import wasi:io/streams
+      import wasi:cli-base/environment
+      import wasi:cli-base/preopens
+      import wasi:cli-base/exit
+      import wasi:cli-base/stdin
+      import wasi:cli-base/stdout
+      import wasi:cli-base/stderr
     ",
     tracing: true,
     async: true,
@@ -26,3 +26,5 @@ wasmtime::component::bindgen!({
         "streams"::"stream-error": Error,
     }
 });
+
+pub use wasi::*;
diff --git a/crates/wasi/wit/command.wit b/crates/wasi/wit/command.wit
deleted file mode 100644
index 29845b60e..000000000
--- a/crates/wasi/wit/command.wit
+++ /dev/null
@@ -1,26 +0,0 @@
-default world command {
-  import wall-clock: clocks.wall-clock
-  import monotonic-clock: clocks.monotonic-clock
-  import timezone: clocks.timezone
-  import filesystem: filesystem.filesystem
-  import instance-network: sockets.instance-network
-  import ip-name-lookup: sockets.ip-name-lookup
-  import network: sockets.network
-  import tcp-create-socket: sockets.tcp-create-socket
-  import tcp: sockets.tcp
-  import udp-create-socket: sockets.udp-create-socket
-  import udp: sockets.udp
-  import random: random.random
-  import insecure-random: random.insecure
-  import insecure-random-seed: random.insecure-seed
-  import poll: poll.poll
-  import streams: io.streams
-  import environment: wasi-cli-base.environment
-  import preopens: wasi-cli-base.preopens
-  import stdin: wasi-cli-base.stdio.stdin
-  import stdout: wasi-cli-base.stdio.stdout
-  import stderr: wasi-cli-base.stdio.stderr
-  import exit: wasi-cli-base.exit
-
-  export run: func() -> result
-}
diff --git a/crates/wasi/wit/deps/clocks/monotonic-clock.wit b/crates/wasi/wit/deps/clocks/monotonic-clock.wit
index 42e2981f5..50eb4de11 100644
--- a/crates/wasi/wit/deps/clocks/monotonic-clock.wit
+++ b/crates/wasi/wit/deps/clocks/monotonic-clock.wit
@@ -1,3 +1,5 @@
+package wasi:clocks
+
 /// WASI Monotonic Clock is a clock API intended to let users measure elapsed
 /// time.
 ///
@@ -8,8 +10,8 @@
 /// successive reads of the clock will produce non-decreasing values.
 ///
 /// It is intended for measuring elapsed time.
-default interface monotonic-clock {
-    use poll.poll.{pollable}
+interface monotonic-clock {
+    use wasi:poll/poll.{pollable}
 
     /// A timestamp in nanoseconds.
     type instant = u64
diff --git a/crates/wasi/wit/deps/clocks/timezone.wit b/crates/wasi/wit/deps/clocks/timezone.wit
index 63f99cc40..2b6855668 100644
--- a/crates/wasi/wit/deps/clocks/timezone.wit
+++ b/crates/wasi/wit/deps/clocks/timezone.wit
@@ -1,5 +1,7 @@
-default interface timezone {
-    use pkg.wall-clock.{datetime}
+package wasi:clocks
+
+interface timezone {
+    use wall-clock.{datetime}
 
     /// A timezone.
     ///
diff --git a/crates/wasi/wit/deps/clocks/wall-clock.wit b/crates/wasi/wit/deps/clocks/wall-clock.wit
index 89c5a75da..6137724f6 100644
--- a/crates/wasi/wit/deps/clocks/wall-clock.wit
+++ b/crates/wasi/wit/deps/clocks/wall-clock.wit
@@ -1,3 +1,5 @@
+package wasi:clocks
+
 /// WASI Wall Clock is a clock API intended to let users query the current
 /// time. The name "wall" makes an analogy to a "clock on the wall", which
 /// is not necessarily monotonic as it may be reset.
@@ -12,7 +14,7 @@
 /// monotonic, making it unsuitable for measuring elapsed time.
 ///
 /// It is intended for reporting the current date and time for humans.
-default interface wall-clock {
+interface wall-clock {
     /// A time and date in seconds plus nanoseconds.
     record datetime {
         seconds: u64,
diff --git a/crates/wasi/wit/deps/filesystem/filesystem.wit b/crates/wasi/wit/deps/filesystem/filesystem.wit
index a57164278..2477264a7 100644
--- a/crates/wasi/wit/deps/filesystem/filesystem.wit
+++ b/crates/wasi/wit/deps/filesystem/filesystem.wit
@@ -1,3 +1,5 @@
+package wasi:filesystem
+
 /// WASI filesystem is a filesystem API primarily intended to let users run WASI
 /// programs that access their files on their existing filesystems, without
 /// significant overhead.
@@ -17,9 +19,9 @@
 /// `..` and symbolic link steps, reaches a directory outside of the base
 /// directory, or reaches a symlink to an absolute or rooted path in the
 /// underlying filesystem, the function fails with `error-code::not-permitted`.
-default interface filesystem {
-    use io.streams.{input-stream, output-stream}
-    use clocks.wall-clock.{datetime}
+interface filesystem {
+    use wasi:io/streams.{input-stream, output-stream}
+    use wasi:clocks/wall-clock.{datetime}
 
     /// File size or length of a region within a file.
     type filesize = u64
diff --git a/crates/wasi/wit/deps/http/incoming-handler.wit b/crates/wasi/wit/deps/http/incoming-handler.wit
index 1ecff0aa5..d0e270465 100644
--- a/crates/wasi/wit/deps/http/incoming-handler.wit
+++ b/crates/wasi/wit/deps/http/incoming-handler.wit
@@ -6,8 +6,8 @@
 //   `wasi:http/outgoing-handler` into a single `wasi:http/handler` interface
 //   that takes a `request` parameter and returns a `response` result.
 //
-default interface incoming-handler {
-  use pkg.types.{incoming-request, response-outparam}
+interface incoming-handler {
+  use types.{incoming-request, response-outparam}
 
   // The `handle` function takes an outparam instead of returning its response
   // so that the component may stream its response while streaming any other
diff --git a/crates/wasi/wit/deps/http/outgoing-handler.wit b/crates/wasi/wit/deps/http/outgoing-handler.wit
index abe812ffa..06c8e469f 100644
--- a/crates/wasi/wit/deps/http/outgoing-handler.wit
+++ b/crates/wasi/wit/deps/http/outgoing-handler.wit
@@ -5,8 +5,8 @@
 //   `wasi:http/outgoing-handler` into a single `wasi:http/handler` interface
 //   that takes a `request` parameter and returns a `response` result.
 //
-default interface outgoing-handler {
-  use pkg.types.{outgoing-request, request-options, future-incoming-response}
+interface outgoing-handler {
+  use types.{outgoing-request, request-options, future-incoming-response}
 
   // The parameter and result types of the `handle` function allow the caller
   // to concurrently stream the bodies of the outgoing request and the incoming
diff --git a/crates/wasi/wit/deps/http/types.wit b/crates/wasi/wit/deps/http/types.wit
index bdcf79737..ee4227f42 100644
--- a/crates/wasi/wit/deps/http/types.wit
+++ b/crates/wasi/wit/deps/http/types.wit
@@ -1,10 +1,12 @@
+package wasi:http
+
 // The `wasi:http/types` interface is meant to be imported by components to
 // define the HTTP resource types and operations used by the component's
 // imported and exported interfaces.
-default interface types {
-  use io.streams.{input-stream, output-stream}
-  use poll.poll.{pollable}
-  
+interface types {
+  use wasi:io/streams.{input-stream, output-stream}
+  use wasi:poll/poll.{pollable}
+
   // This type corresponds to HTTP standard Methods.
   variant method {
     get,
diff --git a/crates/wasi/wit/deps/io/streams.wit b/crates/wasi/wit/deps/io/streams.wit
index c1567fd4c..008e36cf5 100644
--- a/crates/wasi/wit/deps/io/streams.wit
+++ b/crates/wasi/wit/deps/io/streams.wit
@@ -1,10 +1,12 @@
+package wasi:io
+
 /// WASI I/O is an I/O abstraction API which is currently focused on providing
 /// stream types.
 ///
 /// In the future, the component model is expected to add built-in stream types;
 /// when it does, they are expected to subsume this API.
-default interface streams {
-    use poll.poll.{pollable}
+interface streams {
+    use wasi:poll/poll.{pollable}
 
     /// An error type returned from a stream operation. Currently this
     /// doesn't provide any additional information.
diff --git a/crates/wasi/wit/deps/logging/handler.wit b/crates/wasi/wit/deps/logging/handler.wit
index c9632b9cc..e6b077be8 100644
--- a/crates/wasi/wit/deps/logging/handler.wit
+++ b/crates/wasi/wit/deps/logging/handler.wit
@@ -1,6 +1,8 @@
+package wasi:logging
+
 /// WASI Logging is a logging API intended to let users emit log messages with
 /// simple priority levels and context values.
-default interface handler {
+interface handler {
     /// A log level, describing a kind of message.
     enum level {
        /// Describes messages about the values of variables and the flow of
diff --git a/crates/wasi/wit/deps/poll/poll.wit b/crates/wasi/wit/deps/poll/poll.wit
index 28f08e17d..cf5d8779c 100644
--- a/crates/wasi/wit/deps/poll/poll.wit
+++ b/crates/wasi/wit/deps/poll/poll.wit
@@ -1,6 +1,8 @@
+package wasi:poll
+
 /// A poll API intended to let users wait for I/O events on multiple handles
 /// at once.
-default interface poll {
+interface poll {
     /// A "pollable" handle.
     ///
     /// This is conceptually represents a `stream<_, _>`, or in other words,
diff --git a/crates/wasi/wit/deps/preview/command-extended.wit b/crates/wasi/wit/deps/preview/command-extended.wit
index 92e3d7d81..2beb119da 100644
--- a/crates/wasi/wit/deps/preview/command-extended.wit
+++ b/crates/wasi/wit/deps/preview/command-extended.wit
@@ -1,29 +1,34 @@
-default world command-extended {
-  import wall-clock: clocks.wall-clock
-  import monotonic-clock: clocks.monotonic-clock
-  import timezone: clocks.timezone
-  import filesystem: filesystem.filesystem
-  import instance-network: sockets.instance-network
-  import ip-name-lookup: sockets.ip-name-lookup
-  import network: sockets.network
-  import tcp-create-socket: sockets.tcp-create-socket
-  import tcp: sockets.tcp
-  import udp-create-socket: sockets.udp-create-socket
-  import udp: sockets.udp
-  import random: random.random
-  import insecure-random: random.insecure
-  import insecure-random-seed: random.insecure-seed
-  import poll: poll.poll
-  import streams: io.streams
-  import environment: wasi-cli-base.environment
-  import preopens: wasi-cli-base.preopens
-  import exit: wasi-cli-base.exit
+package wasi:preview
+
+world command-extended {
+  import wasi:clocks/wall-clock
+  import wasi:clocks/monotonic-clock
+  import wasi:clocks/timezone
+  import wasi:filesystem/filesystem
+  import wasi:sockets/instance-network
+  import wasi:sockets/ip-name-lookup
+  import wasi:sockets/network
+  import wasi:sockets/tcp-create-socket
+  import wasi:sockets/tcp
+  import wasi:sockets/udp-create-socket
+  import wasi:sockets/udp
+  import wasi:random/random
+  import wasi:random/insecure
+  import wasi:random/insecure-seed
+  import wasi:poll/poll
+  import wasi:io/streams
+  import wasi:cli-base/environment
+  import wasi:cli-base/preopens
+  import wasi:cli-base/exit
+  import wasi:cli-base/stdin
+  import wasi:cli-base/stdout
+  import wasi:cli-base/stderr
 
   // We should replace all others with `include self.command`
   // as soon as the unioning of worlds is available:
   // https://github.com/WebAssembly/component-model/issues/169
-  import console: logging.handler
-  import default-outgoing-HTTP: http.outgoing-handler
+  import wasi:logging/handler
+  import wasi:http/outgoing-handler
 
   export run: func(
     args: list<string>,
diff --git a/crates/wasi/wit/deps/preview/command.wit b/crates/wasi/wit/deps/preview/command.wit
index 780e2c466..62608a05c 100644
--- a/crates/wasi/wit/deps/preview/command.wit
+++ b/crates/wasi/wit/deps/preview/command.wit
@@ -1,23 +1,26 @@
-default world command {
-  import wall-clock: clocks.wall-clock
-  import monotonic-clock: clocks.monotonic-clock
-  import timezone: clocks.timezone
-  import filesystem: filesystem.filesystem
-  import instance-network: sockets.instance-network
-  import ip-name-lookup: sockets.ip-name-lookup
-  import network: sockets.network
-  import tcp-create-socket: sockets.tcp-create-socket
-  import tcp: sockets.tcp
-  import udp-create-socket: sockets.udp-create-socket
-  import udp: sockets.udp
-  import random: random.random
-  import insecure-random: random.insecure
-  import insecure-random-seed: random.insecure-seed
-  import poll: poll.poll
-  import streams: io.streams
-  import environment: wasi-cli-base.environment
-  import preopens: wasi-cli-base.preopens
-  import exit: wasi-cli-base.exit
+world command {
+  import wasi:clocks/wall-clock
+  import wasi:clocks/monotonic-clock
+  import wasi:clocks/timezone
+  import wasi:filesystem/filesystem
+  import wasi:sockets/instance-network
+  import wasi:sockets/ip-name-lookup
+  import wasi:sockets/network
+  import wasi:sockets/tcp-create-socket
+  import wasi:sockets/tcp
+  import wasi:sockets/udp-create-socket
+  import wasi:sockets/udp
+  import wasi:random/random
+  import wasi:random/insecure
+  import wasi:random/insecure-seed
+  import wasi:poll/poll
+  import wasi:io/streams
+  import wasi:cli-base/environment
+  import wasi:cli-base/preopens
+  import wasi:cli-base/exit
+  import wasi:cli-base/stdin
+  import wasi:cli-base/stdout
+  import wasi:cli-base/stderr
 
   export run: func() -> result
 }
diff --git a/crates/wasi/wit/deps/preview/proxy.wit b/crates/wasi/wit/deps/preview/proxy.wit
index 03877e958..a616daa1c 100644
--- a/crates/wasi/wit/deps/preview/proxy.wit
+++ b/crates/wasi/wit/deps/preview/proxy.wit
@@ -1,8 +1,9 @@
-default world proxy {
-  import random: random.random
-  import insecure-random: random.insecure
-  import insecure-random-seed: random.insecure-seed
-  import console: logging.handler
-  import default-outgoing-HTTP: http.outgoing-handler
-  export HTTP: http.incoming-handler
+world proxy {
+  import wasi:random/random
+  import wasi:random/insecure
+  import wasi:random/insecure-seed
+  import wasi:logging/handler
+  import wasi:http/outgoing-handler
+
+  export wasi:http/incoming-handler
 }
diff --git a/crates/wasi/wit/deps/preview/reactor.wit b/crates/wasi/wit/deps/preview/reactor.wit
index 2abfa466b..4a262c551 100644
--- a/crates/wasi/wit/deps/preview/reactor.wit
+++ b/crates/wasi/wit/deps/preview/reactor.wit
@@ -1,21 +1,24 @@
-default world reactor {
-  import wall-clock: clocks.wall-clock
-  import monotonic-clock: clocks.monotonic-clock
-  import timezone: clocks.timezone
-  import filesystem: filesystem.filesystem
-  import instance-network: sockets.instance-network
-  import ip-name-lookup: sockets.ip-name-lookup
-  import network: sockets.network
-  import tcp-create-socket: sockets.tcp-create-socket
-  import tcp: sockets.tcp
-  import udp-create-socket: sockets.udp-create-socket
-  import udp: sockets.udp
-  import random: random.random
-  import poll: poll.poll
-  import streams: io.streams
-  import console: logging.handler
-  import default-outgoing-HTTP: http.outgoing-handler
-  import environment: wasi-cli-base.environment
-  import preopens: wasi-cli-base.preopens
-  import exit: wasi-cli-base.exit
+world reactor {
+  import wasi:clocks/wall-clock
+  import wasi:clocks/monotonic-clock
+  import wasi:clocks/timezone
+  import wasi:filesystem/filesystem
+  import wasi:sockets/instance-network
+  import wasi:sockets/ip-name-lookup
+  import wasi:sockets/network
+  import wasi:sockets/tcp-create-socket
+  import wasi:sockets/tcp
+  import wasi:sockets/udp-create-socket
+  import wasi:sockets/udp
+  import wasi:random/random
+  import wasi:poll/poll
+  import wasi:io/streams
+  import wasi:logging/handler
+  import wasi:http/outgoing-handler
+  import wasi:cli-base/environment
+  import wasi:cli-base/preopens
+  import wasi:cli-base/exit
+  import wasi:cli-base/stdin
+  import wasi:cli-base/stdout
+  import wasi:cli-base/stderr
 }
diff --git a/crates/wasi/wit/deps/random/insecure-seed.wit b/crates/wasi/wit/deps/random/insecure-seed.wit
index 93a2f17d4..ff2ff65d0 100644
--- a/crates/wasi/wit/deps/random/insecure-seed.wit
+++ b/crates/wasi/wit/deps/random/insecure-seed.wit
@@ -2,7 +2,7 @@
 ///
 /// It is intended to be portable at least between Unix-family platforms and
 /// Windows.
-default interface insecure-seed {
+interface insecure-seed {
     /// Return a 128-bit value that may contain a pseudo-random value.
     ///
     /// The returned value is not required to be computed from a CSPRNG, and may
diff --git a/crates/wasi/wit/deps/random/insecure.wit b/crates/wasi/wit/deps/random/insecure.wit
index 1ef020a09..ff0826822 100644
--- a/crates/wasi/wit/deps/random/insecure.wit
+++ b/crates/wasi/wit/deps/random/insecure.wit
@@ -2,7 +2,7 @@
 ///
 /// It is intended to be portable at least between Unix-family platforms and
 /// Windows.
-default interface insecure {
+interface insecure {
     /// Return `len` insecure pseudo-random bytes.
     ///
     /// This function is not cryptographically secure. Do not use it for
diff --git a/crates/wasi/wit/deps/random/random.wit b/crates/wasi/wit/deps/random/random.wit
index 8f7585788..f2bd6358c 100644
--- a/crates/wasi/wit/deps/random/random.wit
+++ b/crates/wasi/wit/deps/random/random.wit
@@ -1,8 +1,10 @@
+package wasi:random
+
 /// WASI Random is a random data API.
 ///
 /// It is intended to be portable at least between Unix-family platforms and
 /// Windows.
-default interface random {
+interface random {
     /// Return `len` cryptographically-secure pseudo-random bytes.
     ///
     /// This function must produce data from an adequately seeded
diff --git a/crates/wasi/wit/deps/sockets/instance-network.wit b/crates/wasi/wit/deps/sockets/instance-network.wit
index b1f5c982d..d911a29cc 100644
--- a/crates/wasi/wit/deps/sockets/instance-network.wit
+++ b/crates/wasi/wit/deps/sockets/instance-network.wit
@@ -1,7 +1,7 @@
 
 /// This interface provides a value-export of the default network handle..
-default interface instance-network {
-	use pkg.network.{network}
+interface instance-network {
+	use network.{network}
 
 	/// Get a handle to the default network.
 	instance-network: func() -> network
diff --git a/crates/wasi/wit/deps/sockets/ip-name-lookup.wit b/crates/wasi/wit/deps/sockets/ip-name-lookup.wit
index c4cc72684..6c64b4617 100644
--- a/crates/wasi/wit/deps/sockets/ip-name-lookup.wit
+++ b/crates/wasi/wit/deps/sockets/ip-name-lookup.wit
@@ -1,13 +1,13 @@
 
-default interface ip-name-lookup {
-	use poll.poll.{pollable}
-	use pkg.network.{network, error-code, ip-address, ip-address-family}
+interface ip-name-lookup {
+	use wasi:poll/poll.{pollable}
+	use network.{network, error-code, ip-address, ip-address-family}
 
 
 	/// Resolve an internet host name to a list of IP addresses.
-	/// 
+	///
 	/// See the wasi-socket proposal README.md for a comparison with getaddrinfo.
-	/// 
+	///
 	/// # Parameters
 	/// - `name`: The name to look up. IP addresses are not allowed. Unicode domain names are automatically converted
 	///     to ASCII using IDNA encoding.
@@ -17,18 +17,18 @@ default interface ip-name-lookup {
 	///   systems without an active IPv6 interface. Notes:
 	///     - Even when no public IPv6 interfaces are present or active, names like "localhost" can still resolve to an IPv6 address.
 	///     - Whatever is "available" or "unavailable" is volatile and can change everytime a network cable is unplugged.
-	/// 
+	///
 	/// This function never blocks. It either immediately fails or immediately returns successfully with a `resolve-address-stream`
 	/// that can be used to (asynchronously) fetch the results.
-	/// 
+	///
 	/// At the moment, the stream never completes successfully with 0 items. Ie. the first call
 	/// to `resolve-next-address` never returns `ok(none)`. This may change in the future.
-	/// 
+	///
 	/// # Typical errors
 	/// - `invalid-name`:                 `name` is a syntactically invalid domain name.
 	/// - `invalid-name`:                 `name` is an IP address.
 	/// - `address-family-not-supported`: The specified `address-family` is not supported. (EAI_FAMILY)
-	/// 
+	///
 	/// # References:
 	/// - <https://pubs.opengroup.org/onlinepubs/9699919799/functions/getaddrinfo.html>
 	/// - <https://man7.org/linux/man-pages/man3/getaddrinfo.3.html>
@@ -41,14 +41,14 @@ default interface ip-name-lookup {
     type resolve-address-stream = u32
 
 	/// Returns the next address from the resolver.
-	/// 
+	///
 	/// This function should be called multiple times. On each call, it will
 	/// return the next address in connection order preference. If all
 	/// addresses have been exhausted, this function returns `none`.
 	/// After which, you should release the stream with `drop-resolve-address-stream`.
-	/// 
+	///
 	/// This function never returns IPv4-mapped IPv6 addresses.
-	/// 
+	///
 	/// # Typical errors
 	/// - `name-unresolvable`:          Name does not exist or has no suitable associated IP addresses. (EAI_NONAME, EAI_NODATA, EAI_ADDRFAMILY)
 	/// - `temporary-resolver-failure`: A temporary failure in name resolution occurred. (EAI_AGAIN)
@@ -57,12 +57,12 @@ default interface ip-name-lookup {
 	resolve-next-address: func(this: resolve-address-stream) -> result<option<ip-address>, error-code>
 
 	/// Dispose of the specified `resolve-address-stream`, after which it may no longer be used.
-	/// 
+	///
 	/// Note: this function is scheduled to be removed when Resources are natively supported in Wit.
 	drop-resolve-address-stream: func(this: resolve-address-stream)
 
 	/// Create a `pollable` which will resolve once the stream is ready for I/O.
-	/// 
+	///
 	/// Note: this function is here for WASI Preview2 only.
 	/// It's planned to be removed when `future` is natively supported in Preview3.
 	subscribe: func(this: resolve-address-stream) -> pollable
diff --git a/crates/wasi/wit/deps/sockets/network.wit b/crates/wasi/wit/deps/sockets/network.wit
index 9176e6ba6..c370214ce 100644
--- a/crates/wasi/wit/deps/sockets/network.wit
+++ b/crates/wasi/wit/deps/sockets/network.wit
@@ -1,14 +1,15 @@
+package wasi:sockets
 
-default interface network {
+interface network {
     /// An opaque resource that represents access to (a subset of) the network.
 	/// This enables context-based security for networking.
 	/// There is no need for this to map 1:1 to a physical network interface.
-	/// 
+	///
 	/// FYI, In the future this will be replaced by handle types.
     type network = u32
 
 	/// Dispose of the specified `network`, after which it may no longer be used.
-	/// 
+	///
 	/// Note: this function is scheduled to be removed when Resources are natively supported in Wit.
 	drop-network: func(this: network)
 
@@ -152,7 +153,7 @@ default interface network {
 
 	enum ip-address-family {
 		/// Similar to `AF_INET` in POSIX.
-		ipv4, 
+		ipv4,
 
 		/// Similar to `AF_INET6` in POSIX.
 		ipv6,
@@ -183,4 +184,4 @@ default interface network {
 		ipv6(ipv6-socket-address),
 	}
 
-}
\ No newline at end of file
+}
diff --git a/crates/wasi/wit/deps/sockets/tcp-create-socket.wit b/crates/wasi/wit/deps/sockets/tcp-create-socket.wit
index 6e948fae0..f467d2856 100644
--- a/crates/wasi/wit/deps/sockets/tcp-create-socket.wit
+++ b/crates/wasi/wit/deps/sockets/tcp-create-socket.wit
@@ -1,23 +1,23 @@
 
-default interface tcp-create-socket {
-	use pkg.network.{network, error-code, ip-address-family}
-	use pkg.tcp.{tcp-socket}
+interface tcp-create-socket {
+	use network.{network, error-code, ip-address-family}
+	use tcp.{tcp-socket}
 
 	/// Create a new TCP socket.
-	/// 
+	///
 	/// Similar to `socket(AF_INET or AF_INET6, SOCK_STREAM, IPPROTO_TCP)` in POSIX.
-	/// 
+	///
 	/// This function does not require a network capability handle. This is considered to be safe because
 	/// at time of creation, the socket is not bound to any `network` yet. Up to the moment `bind`/`listen`/`connect`
 	/// is called, the socket is effectively an in-memory configuration object, unable to communicate with the outside world.
-	/// 
+	///
 	/// All sockets are non-blocking. Use the wasi-poll interface to block on asynchronous operations.
-	/// 
+	///
 	/// # Typical errors
 	/// - `not-supported`:                The host does not support TCP sockets. (EOPNOTSUPP)
 	/// - `address-family-not-supported`: The specified `address-family` is not supported. (EAFNOSUPPORT)
 	/// - `new-socket-limit`:             The new socket resource could not be created because of a system limit. (EMFILE, ENFILE)
-	/// 
+	///
 	/// # References
 	/// - <https://pubs.opengroup.org/onlinepubs/9699919799/functions/socket.html>
 	/// - <https://man7.org/linux/man-pages/man2/socket.2.html>
diff --git a/crates/wasi/wit/deps/sockets/tcp.wit b/crates/wasi/wit/deps/sockets/tcp.wit
index b87153243..7ed46a690 100644
--- a/crates/wasi/wit/deps/sockets/tcp.wit
+++ b/crates/wasi/wit/deps/sockets/tcp.wit
@@ -1,12 +1,12 @@
 
-default interface tcp {
-	use io.streams.{input-stream, output-stream}
-	use poll.poll.{pollable}
-	use pkg.network.{network, error-code, ip-socket-address, ip-address-family}
+interface tcp {
+	use wasi:io/streams.{input-stream, output-stream}
+	use wasi:poll/poll.{pollable}
+	use network.{network, error-code, ip-socket-address, ip-address-family}
 
 	/// A TCP socket handle.
 	type tcp-socket = u32
-	
+
 
 	enum shutdown-type {
 		/// Similar to `SHUT_RD` in POSIX.
@@ -25,24 +25,24 @@ default interface tcp {
 	/// If the IP address is zero (`0.0.0.0` in IPv4, `::` in IPv6), it is left to the implementation to decide which
 	/// network interface(s) to bind to.
 	/// If the TCP/UDP port is zero, the socket will be bound to a random free port.
-	/// 
+	///
 	/// When a socket is not explicitly bound, the first invocation to a listen or connect operation will
 	/// implicitly bind the socket.
-	/// 
+	///
 	/// Unlike in POSIX, this function is async. This enables interactive WASI hosts to inject permission prompts.
-	/// 
+	///
 	/// # Typical `start` errors
 	/// - `address-family-mismatch`:   The `local-address` has the wrong address family. (EINVAL)
 	/// - `already-bound`:             The socket is already bound. (EINVAL)
 	/// - `concurrency-conflict`:      Another `bind`, `connect` or `listen` operation is already in progress. (EALREADY)
-	/// 
+	///
 	/// # Typical `finish` errors
 	/// - `ephemeral-ports-exhausted`: No ephemeral ports available. (EADDRINUSE, ENOBUFS on Windows)
 	/// - `address-in-use`:            Address is already in use. (EADDRINUSE)
 	/// - `address-not-bindable`:      `local-address` is not an address that the `network` can bind to. (EADDRNOTAVAIL)
 	/// - `not-in-progress`:           A `bind` operation is not in progress.
 	/// - `would-block`:               Can't finish the operation, it is still in progress. (EWOULDBLOCK, EAGAIN)
-	/// 
+	///
 	/// # References
 	/// - <https://pubs.opengroup.org/onlinepubs/9699919799/functions/bind.html>
 	/// - <https://man7.org/linux/man-pages/man2/bind.2.html>
@@ -52,11 +52,11 @@ default interface tcp {
 	finish-bind: func(this: tcp-socket) -> result<_, error-code>
 
 	/// Connect to a remote endpoint.
-	/// 
+	///
 	/// On success:
 	/// - the socket is transitioned into the Connection state
 	/// - a pair of streams is returned that can be used to read & write to the connection
-	/// 
+	///
 	/// # Typical `start` errors
 	/// - `address-family-mismatch`:   The `remote-address` has the wrong address family. (EAFNOSUPPORT)
 	/// - `invalid-remote-address`:    The IP address in `remote-address` is set to INADDR_ANY (`0.0.0.0` / `::`). (EADDRNOTAVAIL on Windows)
@@ -65,7 +65,7 @@ default interface tcp {
 	/// - `already-connected`:         The socket is already in the Connection state. (EISCONN)
 	/// - `already-listening`:         The socket is already in the Listener state. (EOPNOTSUPP, EINVAL on Windows)
 	/// - `concurrency-conflict`:      Another `bind`, `connect` or `listen` operation is already in progress. (EALREADY)
-	/// 
+	///
 	/// # Typical `finish` errors
 	/// - `timeout`:                   Connection timed out. (ETIMEDOUT)
 	/// - `connection-refused`:        The connection was forcefully rejected. (ECONNREFUSED)
@@ -74,7 +74,7 @@ default interface tcp {
 	/// - `ephemeral-ports-exhausted`: Tried to perform an implicit bind, but there were no ephemeral ports available. (EADDRINUSE, EADDRNOTAVAIL on Linux, EAGAIN on BSD)
 	/// - `not-in-progress`:           A `connect` operation is not in progress.
 	/// - `would-block`:               Can't finish the operation, it is still in progress. (EWOULDBLOCK, EAGAIN)
-	/// 
+	///
 	/// # References
 	/// - <https://pubs.opengroup.org/onlinepubs/9699919799/functions/connect.html>
 	/// - <https://man7.org/linux/man-pages/man2/connect.2.html>
@@ -84,11 +84,11 @@ default interface tcp {
 	finish-connect: func(this: tcp-socket) -> result<tuple<input-stream, output-stream>, error-code>
 
 	/// Start listening for new connections.
-	/// 
+	///
 	/// Transitions the socket into the Listener state.
-	/// 
+	///
 	/// Unlike in POSIX, this function is async. This enables interactive WASI hosts to inject permission prompts.
-	/// 
+	///
 	/// # Typical `start` errors
 	/// - `already-attached`:          The socket is already attached to a different network. The `network` passed to `listen` must be identical to the one passed to `bind`.
 	/// - `already-connected`:         The socket is already in the Connection state. (EISCONN, EINVAL on BSD)
@@ -109,18 +109,18 @@ default interface tcp {
 	finish-listen: func(this: tcp-socket) -> result<_, error-code>
 
 	/// Accept a new client socket.
-	/// 
+	///
 	/// The returned socket is bound and in the Connection state.
-	/// 
+	///
 	/// On success, this function returns the newly accepted client socket along with
 	/// a pair of streams that can be used to read & write to the connection.
-	/// 
+	///
 	/// # Typical errors
 	/// - `not-listening`: Socket is not in the Listener state. (EINVAL)
 	/// - `would-block`:   No pending connections at the moment. (EWOULDBLOCK, EAGAIN)
-	/// 
+	///
 	/// Host implementations must skip over transient errors returned by the native accept syscall.
-	/// 
+	///
 	/// # References
 	/// - <https://pubs.opengroup.org/onlinepubs/9699919799/functions/accept.html>
 	/// - <https://man7.org/linux/man-pages/man2/accept.2.html>
@@ -129,10 +129,10 @@ default interface tcp {
 	accept: func(this: tcp-socket) -> result<tuple<tcp-socket, input-stream, output-stream>, error-code>
 
 	/// Get the bound local address.
-	/// 
+	///
 	/// # Typical errors
 	/// - `not-bound`: The socket is not bound to any local address.
-	/// 
+	///
 	/// # References
 	/// - <https://pubs.opengroup.org/onlinepubs/9699919799/functions/getsockname.html>
 	/// - <https://man7.org/linux/man-pages/man2/getsockname.2.html>
@@ -141,10 +141,10 @@ default interface tcp {
 	local-address: func(this: tcp-socket) -> result<ip-socket-address, error-code>
 
 	/// Get the bound remote address.
-	/// 
+	///
 	/// # Typical errors
 	/// - `not-connected`: The socket is not connected to a remote address. (ENOTCONN)
-	/// 
+	///
 	/// # References
 	/// - <https://pubs.opengroup.org/onlinepubs/9699919799/functions/getpeername.html>
 	/// - <https://man7.org/linux/man-pages/man2/getpeername.2.html>
@@ -153,14 +153,14 @@ default interface tcp {
 	remote-address: func(this: tcp-socket) -> result<ip-socket-address, error-code>
 
 	/// Whether this is a IPv4 or IPv6 socket.
-	/// 
+	///
 	/// Equivalent to the SO_DOMAIN socket option.
 	address-family: func(this: tcp-socket) -> ip-address-family
-	
+
 	/// Whether IPv4 compatibility (dual-stack) mode is disabled or not.
-	/// 
+	///
 	/// Equivalent to the IPV6_V6ONLY socket option.
-	/// 
+	///
 	/// # Typical errors
 	/// - `ipv6-only-operation`:  (get/set) `this` socket is an IPv4 socket.
 	/// - `already-bound`:        (set) The socket is already bound.
@@ -170,28 +170,28 @@ default interface tcp {
 	set-ipv6-only: func(this: tcp-socket, value: bool) -> result<_, error-code>
 
 	/// Hints the desired listen queue size. Implementations are free to ignore this.
-	/// 
+	///
 	/// # Typical errors
 	/// - `already-connected`:    (set) The socket is already in the Connection state.
 	/// - `concurrency-conflict`: (set) A `bind`, `connect` or `listen` operation is already in progress. (EALREADY)
 	set-listen-backlog-size: func(this: tcp-socket, value: u64) -> result<_, error-code>
 
 	/// Equivalent to the SO_KEEPALIVE socket option.
-	/// 
+	///
 	/// # Typical errors
 	/// - `concurrency-conflict`: (set) A `bind`, `connect` or `listen` operation is already in progress. (EALREADY)
 	keep-alive: func(this: tcp-socket) -> result<bool, error-code>
 	set-keep-alive: func(this: tcp-socket, value: bool) -> result<_, error-code>
 
 	/// Equivalent to the TCP_NODELAY socket option.
-	/// 
+	///
 	/// # Typical errors
 	/// - `concurrency-conflict`: (set) A `bind`, `connect` or `listen` operation is already in progress. (EALREADY)
 	no-delay: func(this: tcp-socket) -> result<bool, error-code>
 	set-no-delay: func(this: tcp-socket, value: bool) -> result<_, error-code>
-	
+
 	/// Equivalent to the IP_TTL & IPV6_UNICAST_HOPS socket options.
-	/// 
+	///
 	/// # Typical errors
 	/// - `already-connected`:    (set) The socket is already in the Connection state.
 	/// - `already-listening`:    (set) The socket is already in the Listener state.
@@ -200,16 +200,16 @@ default interface tcp {
 	set-unicast-hop-limit: func(this: tcp-socket, value: u8) -> result<_, error-code>
 
 	/// The kernel buffer space reserved for sends/receives on this socket.
-	/// 
+	///
 	/// Note #1: an implementation may choose to cap or round the buffer size when setting the value.
 	/// 	In other words, after setting a value, reading the same setting back may return a different value.
-	/// 
+	///
 	/// Note #2: there is not necessarily a direct relationship between the kernel buffer size and the bytes of
 	/// 	actual data to be sent/received by the application, because the kernel might also use the buffer space
 	/// 	for internal metadata structures.
-	/// 
+	///
 	/// Equivalent to the SO_RCVBUF and SO_SNDBUF socket options.
-	/// 
+	///
 	/// # Typical errors
 	/// - `already-connected`:    (set) The socket is already in the Connection state.
 	/// - `already-listening`:    (set) The socket is already in the Listener state.
@@ -220,25 +220,25 @@ default interface tcp {
 	set-send-buffer-size: func(this: tcp-socket, value: u64) -> result<_, error-code>
 
 	/// Create a `pollable` which will resolve once the socket is ready for I/O.
-	/// 
+	///
 	/// Note: this function is here for WASI Preview2 only.
 	/// It's planned to be removed when `future` is natively supported in Preview3.
 	subscribe: func(this: tcp-socket) -> pollable
 
 	/// Initiate a graceful shutdown.
-	/// 
+	///
 	/// - receive: the socket is not expecting to receive any more data from the peer. All subsequent read
 	///   operations on the `input-stream` associated with this socket will return an End Of Stream indication.
 	///   Any data still in the receive queue at time of calling `shutdown` will be discarded.
 	/// - send: the socket is not expecting to send any more data to the peer. All subsequent write
 	///   operations on the `output-stream` associated with this socket will return an error.
 	/// - both: same effect as receive & send combined.
-	/// 
+	///
 	/// The shutdown function does not close (drop) the socket.
-	/// 
+	///
 	/// # Typical errors
 	/// - `not-connected`: The socket is not in the Connection state. (ENOTCONN)
-	/// 
+	///
 	/// # References
 	/// - <https://pubs.opengroup.org/onlinepubs/9699919799/functions/shutdown.html>
 	/// - <https://man7.org/linux/man-pages/man2/shutdown.2.html>
@@ -247,9 +247,9 @@ default interface tcp {
 	shutdown: func(this: tcp-socket, shutdown-type: shutdown-type) -> result<_, error-code>
 
 	/// Dispose of the specified `tcp-socket`, after which it may no longer be used.
-	/// 
+	///
 	/// Similar to the POSIX `close` function.
-	/// 
+	///
 	/// Note: this function is scheduled to be removed when Resources are natively supported in Wit.
 	drop-tcp-socket: func(this: tcp-socket)
 }
diff --git a/crates/wasi/wit/deps/sockets/udp-create-socket.wit b/crates/wasi/wit/deps/sockets/udp-create-socket.wit
index 2c987be08..1cfbd7f0b 100644
--- a/crates/wasi/wit/deps/sockets/udp-create-socket.wit
+++ b/crates/wasi/wit/deps/sockets/udp-create-socket.wit
@@ -1,23 +1,23 @@
 
-default interface udp-create-socket {
-	use pkg.network.{network, error-code, ip-address-family}
-	use pkg.udp.{udp-socket}
+interface udp-create-socket {
+	use network.{network, error-code, ip-address-family}
+	use udp.{udp-socket}
 
 	/// Create a new UDP socket.
-	/// 
+	///
 	/// Similar to `socket(AF_INET or AF_INET6, SOCK_DGRAM, IPPROTO_UDP)` in POSIX.
-	/// 
+	///
 	/// This function does not require a network capability handle. This is considered to be safe because
 	/// at time of creation, the socket is not bound to any `network` yet. Up to the moment `bind`/`connect` is called,
 	/// the socket is effectively an in-memory configuration object, unable to communicate with the outside world.
-	/// 
+	///
 	/// All sockets are non-blocking. Use the wasi-poll interface to block on asynchronous operations.
-	/// 
+	///
 	/// # Typical errors
 	/// - `not-supported`:                The host does not support UDP sockets. (EOPNOTSUPP)
 	/// - `address-family-not-supported`: The specified `address-family` is not supported. (EAFNOSUPPORT)
 	/// - `new-socket-limit`:             The new socket resource could not be created because of a system limit. (EMFILE, ENFILE)
-	/// 
+	///
 	/// # References:
 	/// - <https://pubs.opengroup.org/onlinepubs/9699919799/functions/socket.html>
 	/// - <https://man7.org/linux/man-pages/man2/socket.2.html>
diff --git a/crates/wasi/wit/deps/sockets/udp.wit b/crates/wasi/wit/deps/sockets/udp.wit
index 271a2cb9f..9dd4573bd 100644
--- a/crates/wasi/wit/deps/sockets/udp.wit
+++ b/crates/wasi/wit/deps/sockets/udp.wit
@@ -1,7 +1,7 @@
 
-default interface udp {
-	use poll.poll.{pollable}
-	use pkg.network.{network, error-code, ip-socket-address, ip-address-family}
+interface udp {
+	use wasi:poll/poll.{pollable}
+	use network.{network, error-code, ip-socket-address, ip-address-family}
 
 
 	/// A UDP socket handle.
@@ -27,23 +27,23 @@ default interface udp {
 	/// If the IP address is zero (`0.0.0.0` in IPv4, `::` in IPv6), it is left to the implementation to decide which
 	/// network interface(s) to bind to.
 	/// If the TCP/UDP port is zero, the socket will be bound to a random free port.
-	/// 
+	///
 	/// When a socket is not explicitly bound, the first invocation to connect will implicitly bind the socket.
-	/// 
+	///
 	/// Unlike in POSIX, this function is async. This enables interactive WASI hosts to inject permission prompts.
-	/// 
+	///
 	/// # Typical `start` errors
 	/// - `address-family-mismatch`:   The `local-address` has the wrong address family. (EINVAL)
 	/// - `already-bound`:             The socket is already bound. (EINVAL)
 	/// - `concurrency-conflict`:      Another `bind` or `connect` operation is already in progress. (EALREADY)
-	/// 
+	///
 	/// # Typical `finish` errors
 	/// - `ephemeral-ports-exhausted`: No ephemeral ports available. (EADDRINUSE, ENOBUFS on Windows)
 	/// - `address-in-use`:            Address is already in use. (EADDRINUSE)
 	/// - `address-not-bindable`:      `local-address` is not an address that the `network` can bind to. (EADDRNOTAVAIL)
 	/// - `not-in-progress`:           A `bind` operation is not in progress.
 	/// - `would-block`:               Can't finish the operation, it is still in progress. (EWOULDBLOCK, EAGAIN)
-	/// 
+	///
 	/// # References
 	/// - <https://pubs.opengroup.org/onlinepubs/9699919799/functions/bind.html>
 	/// - <https://man7.org/linux/man-pages/man2/bind.2.html>
@@ -53,29 +53,29 @@ default interface udp {
 	finish-bind: func(this: udp-socket) -> result<_, error-code>
 
 	/// Set the destination address.
-	/// 
+	///
 	/// The local-address is updated based on the best network path to `remote-address`.
-	/// 
+	///
 	/// When a destination address is set:
 	/// - all receive operations will only return datagrams sent from the provided `remote-address`.
 	/// - the `send` function can only be used to send to this destination.
-	/// 
+	///
 	/// Note that this function does not generate any network traffic and the peer is not aware of this "connection".
-	/// 
+	///
 	/// Unlike in POSIX, this function is async. This enables interactive WASI hosts to inject permission prompts.
-	/// 
+	///
 	/// # Typical `start` errors
 	/// - `address-family-mismatch`:   The `remote-address` has the wrong address family. (EAFNOSUPPORT)
 	/// - `invalid-remote-address`:    The IP address in `remote-address` is set to INADDR_ANY (`0.0.0.0` / `::`). (EDESTADDRREQ, EADDRNOTAVAIL)
 	/// - `invalid-remote-address`:    The port in `remote-address` is set to 0. (EDESTADDRREQ, EADDRNOTAVAIL)
 	/// - `already-attached`:          The socket is already bound to a different network. The `network` passed to `connect` must be identical to the one passed to `bind`.
 	/// - `concurrency-conflict`:      Another `bind` or `connect` operation is already in progress. (EALREADY)
-	/// 
+	///
 	/// # Typical `finish` errors
 	/// - `ephemeral-ports-exhausted`: Tried to perform an implicit bind, but there were no ephemeral ports available. (EADDRINUSE, EADDRNOTAVAIL on Linux, EAGAIN on BSD)
 	/// - `not-in-progress`:           A `connect` operation is not in progress.
 	/// - `would-block`:               Can't finish the operation, it is still in progress. (EWOULDBLOCK, EAGAIN)
-	/// 
+	///
 	/// # References
 	/// - <https://pubs.opengroup.org/onlinepubs/9699919799/functions/connect.html>
 	/// - <https://man7.org/linux/man-pages/man2/connect.2.html>
@@ -85,16 +85,16 @@ default interface udp {
 	finish-connect: func(this: udp-socket) -> result<_, error-code>
 
 	/// Receive a message.
-	/// 
+	///
 	/// Returns:
 	/// - The sender address of the datagram
 	/// - The number of bytes read.
-	/// 
+	///
 	/// # Typical errors
 	/// - `not-bound`:          The socket is not bound to any local address. (EINVAL)
 	/// - `remote-unreachable`: The remote address is not reachable. (ECONNREFUSED, ECONNRESET, ENETRESET on Windows, EHOSTUNREACH, EHOSTDOWN, ENETUNREACH, ENETDOWN)
 	/// - `would-block`:        There is no pending data available to be read at the moment. (EWOULDBLOCK, EAGAIN)
-	/// 
+	///
 	/// # References
 	/// - <https://pubs.opengroup.org/onlinepubs/9699919799/functions/recvfrom.html>
 	/// - <https://pubs.opengroup.org/onlinepubs/9699919799/functions/recvmsg.html>
@@ -106,10 +106,10 @@ default interface udp {
 	receive: func(this: udp-socket) -> result<datagram, error-code>
 
 	/// Send a message to a specific destination address.
-	/// 
+	///
 	/// The remote address option is required. To send a message to the "connected" peer,
 	/// call `remote-address` to get their address.
-	/// 
+	///
 	/// # Typical errors
 	/// - `address-family-mismatch`: The `remote-address` has the wrong address family. (EAFNOSUPPORT)
 	/// - `invalid-remote-address`:  The IP address in `remote-address` is set to INADDR_ANY (`0.0.0.0` / `::`). (EDESTADDRREQ, EADDRNOTAVAIL)
@@ -119,7 +119,7 @@ default interface udp {
 	/// - `remote-unreachable`:      The remote address is not reachable. (ECONNREFUSED, ECONNRESET, ENETRESET on Windows, EHOSTUNREACH, EHOSTDOWN, ENETUNREACH, ENETDOWN)
 	/// - `datagram-too-large`:      The datagram is too large. (EMSGSIZE)
 	/// - `would-block`:             The send buffer is currently full. (EWOULDBLOCK, EAGAIN)
-	/// 
+	///
 	/// # References
 	/// - <https://pubs.opengroup.org/onlinepubs/9699919799/functions/sendto.html>
 	/// - <https://pubs.opengroup.org/onlinepubs/9699919799/functions/sendmsg.html>
@@ -131,10 +131,10 @@ default interface udp {
 	send: func(this: udp-socket, datagram: datagram) -> result<_, error-code>
 
 	/// Get the current bound address.
-	/// 
+	///
 	/// # Typical errors
 	/// - `not-bound`: The socket is not bound to any local address.
-	/// 
+	///
 	/// # References
 	/// - <https://pubs.opengroup.org/onlinepubs/9699919799/functions/getsockname.html>
 	/// - <https://man7.org/linux/man-pages/man2/getsockname.2.html>
@@ -143,10 +143,10 @@ default interface udp {
 	local-address: func(this: udp-socket) -> result<ip-socket-address, error-code>
 
 	/// Get the address set with `connect`.
-	/// 
+	///
 	/// # Typical errors
 	/// - `not-connected`: The socket is not connected to a remote address. (ENOTCONN)
-	/// 
+	///
 	/// # References
 	/// - <https://pubs.opengroup.org/onlinepubs/9699919799/functions/getpeername.html>
 	/// - <https://man7.org/linux/man-pages/man2/getpeername.2.html>
@@ -155,14 +155,14 @@ default interface udp {
 	remote-address: func(this: udp-socket) -> result<ip-socket-address, error-code>
 
 	/// Whether this is a IPv4 or IPv6 socket.
-	/// 
+	///
 	/// Equivalent to the SO_DOMAIN socket option.
 	address-family: func(this: udp-socket) -> ip-address-family
 
 	/// Whether IPv4 compatibility (dual-stack) mode is disabled or not.
-	/// 
+	///
 	/// Equivalent to the IPV6_V6ONLY socket option.
-	/// 
+	///
 	/// # Typical errors
 	/// - `ipv6-only-operation`:  (get/set) `this` socket is an IPv4 socket.
 	/// - `already-bound`:        (set) The socket is already bound.
@@ -172,25 +172,25 @@ default interface udp {
 	set-ipv6-only: func(this: udp-socket, value: bool) -> result<_, error-code>
 
 	/// Equivalent to the IP_TTL & IPV6_UNICAST_HOPS socket options.
-	/// 
+	///
 	/// # Typical errors
 	/// - `concurrency-conflict`: (set) Another `bind` or `connect` operation is already in progress. (EALREADY)
 	unicast-hop-limit: func(this: udp-socket) -> result<u8, error-code>
 	set-unicast-hop-limit: func(this: udp-socket, value: u8) -> result<_, error-code>
 
 	/// The kernel buffer space reserved for sends/receives on this socket.
-	/// 
+	///
 	/// Note #1: an implementation may choose to cap or round the buffer size when setting the value.
 	/// 	In other words, after setting a value, reading the same setting back may return a different value.
-	/// 
+	///
 	/// Note #2: there is not necessarily a direct relationship between the kernel buffer size and the bytes of
 	/// 	actual data to be sent/received by the application, because the kernel might also use the buffer space
 	/// 	for internal metadata structures.
-	/// 
+	///
 	/// Fails when this socket is in the Listening state.
-	/// 
+	///
 	/// Equivalent to the SO_RCVBUF and SO_SNDBUF socket options.
-	/// 
+	///
 	/// # Typical errors
 	/// - `concurrency-conflict`: (set) Another `bind` or `connect` operation is already in progress. (EALREADY)
 	receive-buffer-size: func(this: udp-socket) -> result<u64, error-code>
@@ -199,13 +199,13 @@ default interface udp {
 	set-send-buffer-size: func(this: udp-socket, value: u64) -> result<_, error-code>
 
 	/// Create a `pollable` which will resolve once the socket is ready for I/O.
-	/// 
+	///
 	/// Note: this function is here for WASI Preview2 only.
 	/// It's planned to be removed when `future` is natively supported in Preview3.
 	subscribe: func(this: udp-socket) -> pollable
 
 	/// Dispose of the specified `udp-socket`, after which it may no longer be used.
-	/// 
+	///
 	/// Note: this function is scheduled to be removed when Resources are natively supported in Wit.
 	drop-udp-socket: func(this: udp-socket)
 }
diff --git a/crates/wasi/wit/deps/wasi-cli-base/environment.wit b/crates/wasi/wit/deps/wasi-cli-base/environment.wit
index 876ea3a0c..4c97c85d1 100644
--- a/crates/wasi/wit/deps/wasi-cli-base/environment.wit
+++ b/crates/wasi/wit/deps/wasi-cli-base/environment.wit
@@ -1,4 +1,6 @@
-default interface environment {
+package wasi:cli-base
+
+interface environment {
   /// Get the POSIX-style environment variables.
   ///
   /// Each environment variable is provided as a pair of string variable names
diff --git a/crates/wasi/wit/deps/wasi-cli-base/exit.wit b/crates/wasi/wit/deps/wasi-cli-base/exit.wit
index 2759e9dd9..66835aa70 100644
--- a/crates/wasi/wit/deps/wasi-cli-base/exit.wit
+++ b/crates/wasi/wit/deps/wasi-cli-base/exit.wit
@@ -1,4 +1,4 @@
-default interface wasi-exit {
+interface exit {
   /// Exit the curerent instance and any linked instances.
   exit: func(status: result)
 }
diff --git a/crates/wasi/wit/deps/wasi-cli-base/preopens.wit b/crates/wasi/wit/deps/wasi-cli-base/preopens.wit
index 5595f8d39..f268f6b0b 100644
--- a/crates/wasi/wit/deps/wasi-cli-base/preopens.wit
+++ b/crates/wasi/wit/deps/wasi-cli-base/preopens.wit
@@ -1,6 +1,6 @@
-default interface preopens {
-  use filesystem.filesystem.{descriptor}
-  use io.streams.{input-stream, output-stream}
+interface preopens {
+  use wasi:filesystem/filesystem.{descriptor}
+  use wasi:io/streams.{input-stream, output-stream}
 
   /// Return the set of of preopened directories, and their path.
   get-directories: func() -> list<tuple<descriptor, string>>
diff --git a/crates/wasi/wit/deps/wasi-cli-base/stdio.wit b/crates/wasi/wit/deps/wasi-cli-base/stdio.wit
index 1f87e5485..6c9d4a41a 100644
--- a/crates/wasi/wit/deps/wasi-cli-base/stdio.wit
+++ b/crates/wasi/wit/deps/wasi-cli-base/stdio.wit
@@ -1,17 +1,17 @@
 interface stdin {
-  use io.streams.{input-stream}
+  use wasi:io/streams.{input-stream}
 
   get-stdin: func() -> input-stream
 }
 
 interface stdout {
-  use io.streams.{output-stream}
+  use wasi:io/streams.{output-stream}
 
   get-stdout: func() -> output-stream
 }
 
 interface stderr {
-  use io.streams.{output-stream}
+  use wasi:io/streams.{output-stream}
 
   get-stderr: func() -> output-stream
 }
diff --git a/crates/wasi/wit/main.wit b/crates/wasi/wit/main.wit
new file mode 100644
index 000000000..264dfee82
--- /dev/null
+++ b/crates/wasi/wit/main.wit
@@ -0,0 +1,1 @@
+package unused:main
diff --git a/crates/wasi/wit/reactor.wit b/crates/wasi/wit/reactor.wit
deleted file mode 100644
index fb6b1ac96..000000000
--- a/crates/wasi/wit/reactor.wit
+++ /dev/null
@@ -1,26 +0,0 @@
-default world reactor {
-  import wall-clock: clocks.wall-clock
-  import monotonic-clock: clocks.monotonic-clock
-  import timezone: clocks.timezone
-  import filesystem: filesystem.filesystem
-  import instance-network: sockets.instance-network
-  import ip-name-lookup: sockets.ip-name-lookup
-  import network: sockets.network
-  import tcp-create-socket: sockets.tcp-create-socket
-  import tcp: sockets.tcp
-  import udp-create-socket: sockets.udp-create-socket
-  import udp: sockets.udp
-  import random: random.random
-  import insecure-random: random.insecure
-  import insecure-random-seed: random.insecure-seed
-  import poll: poll.poll
-  import streams: io.streams
-  import console: logging.handler
-  import default-outgoing-HTTP: http.outgoing-handler
-  import environment: wasi-cli-base.environment
-  import preopens: wasi-cli-base.preopens
-  import stdin: wasi-cli-base.stdio.stdin
-  import stdout: wasi-cli-base.stdio.stdout
-  import stderr: wasi-cli-base.stdio.stderr
-  import exit: wasi-cli-base.exit
-}
diff --git a/crates/wasmtime/src/component/matching.rs b/crates/wasmtime/src/component/matching.rs
index 6f2cb5549..0f843032b 100644
--- a/crates/wasmtime/src/component/matching.rs
+++ b/crates/wasmtime/src/component/matching.rs
@@ -72,7 +72,7 @@ impl TypeChecker<'_> {
         // Like modules, every export in the expected type must be present in
         // the actual type. It's ok, though, to have extra exports in the actual
         // type.
-        for (name, (_url, expected)) in expected.exports.iter() {
+        for (name, expected) in expected.exports.iter() {
             // Interface types may be exported from a component in order to give them a name, but
             // they don't have a definition in the sense that this search is interested in, so
             // ignore them.
diff --git a/crates/wasmtime/src/component/mod.rs b/crates/wasmtime/src/component/mod.rs
index 671cce9d0..f2066843e 100644
--- a/crates/wasmtime/src/component/mod.rs
+++ b/crates/wasmtime/src/component/mod.rs
@@ -73,7 +73,9 @@ pub(crate) use self::store::ComponentStoreData;
 /// ```text,ignore
 /// // wit/my-component.wit
 ///
-/// default world hello-world {
+/// package my:project
+///
+/// world hello-world {
 ///     import name: func() -> string
 ///     export greet: func()
 /// }
@@ -150,13 +152,15 @@ pub(crate) use self::store::ComponentStoreData;
 /// ```text,ignore
 /// // wit/my-component.wit
 ///
+/// package my:project
+///
 /// interface host {
 ///     gen-random-integer: func() -> u32
 ///     sha256: func(bytes: list<u8>) -> string
 /// }
 ///
 /// default world hello-world {
-///     import host: self.host
+///     import host
 ///
 ///     export demo: interface {
 ///         run: func()
@@ -169,6 +173,7 @@ pub(crate) use self::store::ComponentStoreData;
 /// ```rust,ignore
 /// use wasmtime::component::*;
 /// use wasmtime::{Config, Engine, Store};
+/// use my::project::host::Host;
 ///
 /// bindgen!();
 ///
@@ -177,7 +182,7 @@ pub(crate) use self::store::ComponentStoreData;
 /// }
 ///
 /// // Note that the trait here is per-interface and within a submodule now.
-/// impl host::Host for MyState {
+/// impl Host for MyState {
 ///     fn gen_random_integer(&mut self) -> wasmtime::Result<u32> {
 ///         Ok(rand::thread_rng().gen())
 ///     }
@@ -228,18 +233,12 @@ pub(crate) use self::store::ComponentStoreData;
 /// bindgen!();
 ///
 /// // Parse the `wit/` folder adjacent to this crate's `Cargo.toml` and look
-/// // for the document `foo`, which must have a `default world` contained
-/// // within it.
+/// // for the world `foo` contained in it.
 /// bindgen!("foo");
 ///
-/// // Parse the `wit/` folder adjacent to `Cargo.toml` and look up the document
-/// // `foo` and the world named `bar`.
-/// bindgen!("foo.bar");
-///
 /// // Parse the folder `other/wit/folder` adjacent to `Cargo.toml`.
 /// bindgen!(in "other/wit/folder");
 /// bindgen!("foo" in "other/wit/folder");
-/// bindgen!("foo.bar" in "other/wit/folder");
 ///
 /// // Parse the file `foo.wit` as a single-file WIT package with no
 /// // dependencies.
@@ -250,8 +249,7 @@ pub(crate) use self::store::ComponentStoreData;
 ///
 /// ```rust,ignore
 /// bindgen!({
-///     world: "foo", // or "foo.bar", same as in `bindgen!("foo")`
-///                   // not needed if `path` has one `default world`
+///     world: "foo", // not needed if `path` has one `world`
 ///
 ///     // same as in `bindgen!(in "other/wit/folder")
 ///     path: "other/wit/folder",
@@ -259,7 +257,9 @@ pub(crate) use self::store::ComponentStoreData;
 ///     // Instead of `path` the WIT document can be provided inline if
 ///     // desired.
 ///     inline: "
-///         default world foo {
+///         package my:inline
+///
+///         world foo {
 ///             // ...
 ///         }
 ///     ",
@@ -295,7 +295,7 @@ pub(crate) use self::store::ComponentStoreData;
 ///     // Restrict the code generated to what's needed for the interface
 ///     // imports in the inlined WIT document fragment.
 ///     interfaces: "
-///         import foo: package.foo;
+///         import package.foo
 ///     ",
 ///
 ///     // Remap interface names to module names, imported from elsewhere.
diff --git a/crates/wit-bindgen/src/lib.rs b/crates/wit-bindgen/src/lib.rs
index a935912aa..26ce89f86 100644
--- a/crates/wit-bindgen/src/lib.rs
+++ b/crates/wit-bindgen/src/lib.rs
@@ -31,28 +31,35 @@ struct InterfaceName {
     remapped: bool,
 
     /// The string name for this interface.
-    name: String,
+    path: String,
 }
 
 #[derive(Default)]
 struct Wasmtime {
     src: Source,
     opts: Opts,
-    imports: Vec<Import>,
+    import_interfaces: BTreeMap<Option<PackageName>, Vec<ImportInterface>>,
+    import_functions: Vec<ImportFunction>,
     exports: Exports,
     types: Types,
     sizes: SizeAlign,
     interface_names: HashMap<InterfaceId, InterfaceName>,
+    with_name_counter: usize,
 }
 
-enum Import {
-    Interface { snake: String },
-    Function { add_to_linker: String, sig: String },
+struct ImportInterface {
+    snake: String,
+    module: String,
+}
+struct ImportFunction {
+    add_to_linker: String,
+    sig: String,
 }
 
 #[derive(Default)]
 struct Exports {
     fields: BTreeMap<String, (String, String)>,
+    modules: BTreeMap<Option<PackageName>, Vec<String>>,
     funcs: Vec<String>,
 }
 
@@ -111,16 +118,33 @@ impl Opts {
 }
 
 impl Wasmtime {
-    fn name_interface(&mut self, id: InterfaceId, name: String) -> bool {
-        let entry = if let Some(remapped_name) = self.opts.with.get(&name) {
+    fn name_interface(&mut self, resolve: &Resolve, id: InterfaceId, name: &WorldKey) -> bool {
+        let with_name = resolve.name_world_key(name);
+        let entry = if let Some(remapped_path) = self.opts.with.get(&with_name) {
+            let name = format!("__with_name{}", self.with_name_counter);
+            self.with_name_counter += 1;
+            uwriteln!(self.src, "use {remapped_path} as {name};");
             InterfaceName {
                 remapped: true,
-                name: remapped_name.clone(),
+                path: name,
             }
         } else {
+            let path = match name {
+                WorldKey::Name(name) => name.to_snake_case(),
+                WorldKey::Interface(_) => {
+                    let iface = &resolve.interfaces[id];
+                    let pkgname = &resolve.packages[iface.package.unwrap()].name;
+                    format!(
+                        "{}::{}::{}",
+                        pkgname.namespace.to_snake_case(),
+                        pkgname.name.to_snake_case(),
+                        iface.name.as_ref().unwrap().to_snake_case()
+                    )
+                }
+            };
             InterfaceName {
                 remapped: false,
-                name,
+                path,
             }
         };
 
@@ -146,30 +170,38 @@ impl Wasmtime {
         self.finish(resolve, id)
     }
 
-    fn import(&mut self, resolve: &Resolve, name: &str, item: &WorldItem) {
-        let snake = name.to_snake_case();
+    fn import(&mut self, resolve: &Resolve, name: &WorldKey, item: &WorldItem) {
         let mut gen = InterfaceGenerator::new(self, resolve);
-        let import = match item {
+        match item {
             WorldItem::Function(func) => {
                 gen.generate_function_trait_sig(TypeOwner::None, func);
                 let sig = mem::take(&mut gen.src).into();
                 gen.generate_add_function_to_linker(TypeOwner::None, func, "linker");
                 let add_to_linker = gen.src.into();
-                Import::Function { sig, add_to_linker }
+                self.import_functions
+                    .push(ImportFunction { sig, add_to_linker });
             }
             WorldItem::Interface(id) => {
-                if gen.gen.name_interface(*id, snake.clone()) {
+                if gen.gen.name_interface(resolve, *id, name) {
                     return;
                 }
-                gen.current_interface = Some(*id);
+                gen.current_interface = Some((*id, name, false));
                 gen.types(*id);
                 gen.generate_trappable_error_types(TypeOwner::Interface(*id));
-                gen.generate_add_to_linker(*id, name);
+                let key_name = resolve.name_world_key(name);
+                gen.generate_add_to_linker(*id, &key_name);
 
                 let module = &gen.src[..];
 
-                uwriteln!(
-                    self.src,
+                let snake = match name {
+                    WorldKey::Name(s) => s.to_snake_case(),
+                    WorldKey::Interface(id) => resolve.interfaces[*id]
+                        .name
+                        .as_ref()
+                        .unwrap()
+                        .to_snake_case(),
+                };
+                let module = format!(
                     "
                         #[allow(clippy::all)]
                         pub mod {snake} {{
@@ -180,40 +212,55 @@ impl Wasmtime {
                         }}
                     "
                 );
-                Import::Interface { snake }
+                let pkg = resolve.interfaces[*id].package.unwrap();
+                let pkgname = match name {
+                    WorldKey::Name(_) => None,
+                    WorldKey::Interface(_) => Some(resolve.packages[pkg].name.clone()),
+                };
+                self.import_interfaces
+                    .entry(pkgname)
+                    .or_insert(Vec::new())
+                    .push(ImportInterface { snake, module });
             }
             WorldItem::Type(ty) => {
+                let name = match name {
+                    WorldKey::Name(name) => name,
+                    WorldKey::Interface(_) => unreachable!(),
+                };
                 gen.define_type(name, *ty);
                 let body = mem::take(&mut gen.src);
                 self.src.push_str(&body);
-                return;
             }
         };
-
-        self.imports.push(import);
     }
 
-    fn export(&mut self, resolve: &Resolve, name: &str, item: &WorldItem) {
-        let snake = name.to_snake_case();
+    fn export(&mut self, resolve: &Resolve, name: &WorldKey, item: &WorldItem) {
         let mut gen = InterfaceGenerator::new(self, resolve);
-        let (ty, getter) = match item {
+        let (field, ty, getter) = match item {
             WorldItem::Function(func) => {
-                gen.define_rust_guest_export(None, func);
+                gen.define_rust_guest_export(resolve, None, func);
                 let body = mem::take(&mut gen.src).into();
                 let (_name, getter) = gen.extract_typed_function(func);
                 assert!(gen.src.is_empty());
                 self.exports.funcs.push(body);
-                ("wasmtime::component::Func".to_string(), getter)
+                (
+                    func.name.to_snake_case(),
+                    "wasmtime::component::Func".to_string(),
+                    getter,
+                )
             }
             WorldItem::Type(_) => unreachable!(),
             WorldItem::Interface(id) => {
-                gen.gen.name_interface(*id, snake.clone());
-                gen.current_interface = Some(*id);
+                gen.gen.name_interface(resolve, *id, name);
+                gen.current_interface = Some((*id, name, true));
                 gen.types(*id);
                 gen.generate_trappable_error_types(TypeOwner::Interface(*id));
                 let iface = &resolve.interfaces[*id];
-
-                let camel = to_rust_upper_camel_case(name);
+                let iface_name = match name {
+                    WorldKey::Name(name) => name,
+                    WorldKey::Interface(_) => iface.name.as_ref().unwrap(),
+                };
+                let camel = to_rust_upper_camel_case(iface_name);
                 uwriteln!(gen.src, "pub struct {camel} {{");
                 for (_, func) in iface.functions.iter() {
                     uwriteln!(
@@ -246,14 +293,14 @@ impl Wasmtime {
                 uwriteln!(gen.src, "}})");
                 uwriteln!(gen.src, "}}");
                 for (_, func) in iface.functions.iter() {
-                    gen.define_rust_guest_export(Some(name), func);
+                    gen.define_rust_guest_export(resolve, Some(name), func);
                 }
                 uwriteln!(gen.src, "}}");
 
                 let module = &gen.src[..];
+                let snake = iface_name.to_snake_case();
 
-                uwriteln!(
-                    self.src,
+                let module = format!(
                     "
                         #[allow(clippy::all)]
                         pub mod {snake} {{
@@ -264,26 +311,54 @@ impl Wasmtime {
                         }}
                     "
                 );
-
+                let pkgname = match name {
+                    WorldKey::Name(_) => None,
+                    WorldKey::Interface(_) => {
+                        Some(resolve.packages[iface.package.unwrap()].name.clone())
+                    }
+                };
+                self.exports
+                    .modules
+                    .entry(pkgname.clone())
+                    .or_insert(Vec::new())
+                    .push(module);
+
+                let name = resolve.name_world_key(name);
+                let (path, method_name) = match pkgname {
+                    Some(pkgname) => (
+                        format!(
+                            "exports::{}::{}::{snake}::{camel}",
+                            pkgname.namespace.to_snake_case(),
+                            pkgname.name.to_snake_case(),
+                        ),
+                        format!(
+                            "{}_{}_{snake}",
+                            pkgname.namespace.to_snake_case(),
+                            pkgname.name.to_snake_case()
+                        ),
+                    ),
+                    None => (format!("exports::{snake}::{camel}"), snake.clone()),
+                };
                 let getter = format!(
                     "\
-                        {snake}::{camel}::new(
+                        {path}::new(
                             &mut __exports.instance(\"{name}\")
                                 .ok_or_else(|| anyhow::anyhow!(\"exported instance `{name}` not present\"))?
                         )?\
                     "
                 );
+                let field = format!("interface{}", self.exports.fields.len());
                 self.exports.funcs.push(format!(
                     "
-                        pub fn {snake}(&self) -> &{snake}::{camel} {{
-                            &self.{snake}
+                        pub fn {method_name}(&self) -> &{path} {{
+                            &self.{field}
                         }}
-                    "
+                    ",
                 ));
-                (format!("{snake}::{camel}"), getter)
+                (field, path, getter)
             }
         };
-        let prev = self.exports.fields.insert(snake.clone(), (ty, getter));
+        let prev = self.exports.fields.insert(field, (ty, getter));
         assert!(prev.is_none());
     }
 
@@ -375,6 +450,20 @@ impl Wasmtime {
             self.build_struct(resolve, world)
         }
 
+        let imports = mem::take(&mut self.import_interfaces);
+        self.emit_modules(
+            &imports
+                .into_iter()
+                .map(|(k, v)| (k, v.into_iter().map(|m| m.module).collect()))
+                .collect(),
+        );
+        if !self.exports.modules.is_empty() {
+            uwriteln!(self.src, "pub mod exports {{");
+            let exports = mem::take(&mut self.exports.modules);
+            self.emit_modules(&exports);
+            uwriteln!(self.src, "}}");
+        }
+
         let mut src = mem::take(&mut self.src);
         if self.opts.rustfmt {
             let mut child = Command::new("rustfmt")
@@ -402,21 +491,42 @@ impl Wasmtime {
 
         src.into()
     }
+
+    fn emit_modules(&mut self, modules: &BTreeMap<Option<PackageName>, Vec<String>>) {
+        let mut map = BTreeMap::new();
+        for (pkg, modules) in modules {
+            match pkg {
+                Some(pkg) => {
+                    let prev = map
+                        .entry(&pkg.namespace)
+                        .or_insert(BTreeMap::new())
+                        .insert(&pkg.name, modules);
+                    assert!(prev.is_none());
+                }
+                None => {
+                    for module in modules {
+                        uwriteln!(self.src, "{module}");
+                    }
+                }
+            }
+        }
+        for (ns, pkgs) in map {
+            uwriteln!(self.src, "pub mod {} {{", ns.to_snake_case());
+            for (pkg, modules) in pkgs {
+                uwriteln!(self.src, "pub mod {} {{", pkg.to_snake_case());
+                for module in modules {
+                    uwriteln!(self.src, "{module}");
+                }
+                uwriteln!(self.src, "}}");
+            }
+            uwriteln!(self.src, "}}");
+        }
+    }
 }
 
 impl Wasmtime {
     fn toplevel_import_trait(&mut self, resolve: &Resolve, world: WorldId) {
-        let mut functions = Vec::new();
-        for import in self.imports.iter() {
-            match import {
-                Import::Interface { .. } => continue,
-                Import::Function {
-                    sig,
-                    add_to_linker: _,
-                } => functions.push(sig),
-            }
-        }
-        if functions.is_empty() {
+        if self.import_functions.is_empty() {
             return;
         }
 
@@ -425,26 +535,29 @@ impl Wasmtime {
             uwriteln!(self.src, "#[wasmtime::component::__internal::async_trait]")
         }
         uwriteln!(self.src, "pub trait {world_camel}Imports {{");
-        for sig in functions {
-            self.src.push_str(sig);
+        for f in self.import_functions.iter() {
+            self.src.push_str(&f.sig);
             self.src.push_str("\n");
         }
         uwriteln!(self.src, "}}");
     }
 
     fn toplevel_add_to_linker(&mut self, resolve: &Resolve, world: WorldId) {
-        if self.imports.is_empty() {
+        if self.import_interfaces.is_empty() && self.import_functions.is_empty() {
             return;
         }
-        let mut functions = Vec::new();
         let mut interfaces = Vec::new();
-        for import in self.imports.iter() {
-            match import {
-                Import::Interface { snake } => interfaces.push(snake),
-                Import::Function {
-                    add_to_linker,
-                    sig: _,
-                } => functions.push(add_to_linker),
+        for (pkg, imports) in self.import_interfaces.iter() {
+            for import in imports {
+                let mut path = String::new();
+                if let Some(pkg) = pkg {
+                    path.push_str(&pkg.namespace.to_snake_case());
+                    path.push_str("::");
+                    path.push_str(&pkg.name.to_snake_case());
+                    path.push_str("::");
+                }
+                path.push_str(&import.snake);
+                interfaces.push(path)
             }
         }
 
@@ -463,7 +576,7 @@ impl Wasmtime {
         for (i, name) in interfaces
             .iter()
             .map(|n| format!("{n}::Host"))
-            .chain(if functions.is_empty() {
+            .chain(if self.import_functions.is_empty() {
                 None
             } else {
                 Some(world_trait.clone())
@@ -485,11 +598,11 @@ impl Wasmtime {
         for name in interfaces.iter() {
             uwriteln!(self.src, "{name}::add_to_linker(linker, get)?;");
         }
-        if !functions.is_empty() {
+        if !self.import_functions.is_empty() {
             uwriteln!(self.src, "Self::add_root_to_linker(linker, get)?;");
         }
         uwriteln!(self.src, "Ok(())\n}}");
-        if functions.is_empty() {
+        if self.import_functions.is_empty() {
             return;
         }
 
@@ -505,8 +618,8 @@ impl Wasmtime {
                     let mut linker = linker.root();
             ",
         );
-        for add_to_linker in functions {
-            self.src.push_str(add_to_linker);
+        for f in self.import_functions.iter() {
+            self.src.push_str(&f.add_to_linker);
             self.src.push_str("\n");
         }
         uwriteln!(self.src, "Ok(())\n}}");
@@ -517,7 +630,7 @@ struct InterfaceGenerator<'a> {
     src: Source,
     gen: &'a mut Wasmtime,
     resolve: &'a Resolve,
-    current_interface: Option<InterfaceId>,
+    current_interface: Option<(InterfaceId, &'a WorldKey, bool)>,
 }
 
 impl<'a> InterfaceGenerator<'a> {
@@ -1263,7 +1376,12 @@ impl<'a> InterfaceGenerator<'a> {
         ret
     }
 
-    fn define_rust_guest_export(&mut self, ns: Option<&str>, func: &Function) {
+    fn define_rust_guest_export(
+        &mut self,
+        resolve: &Resolve,
+        ns: Option<&WorldKey>,
+        func: &Function,
+    ) {
         let (async_, async__, await_) = if self.gen.opts.async_ {
             ("async", "_async", ".await")
         } else {
@@ -1292,17 +1410,20 @@ impl<'a> InterfaceGenerator<'a> {
         }
 
         if self.gen.opts.tracing {
+            let ns = match ns {
+                Some(key) => resolve.name_world_key(key),
+                None => "default".to_string(),
+            };
             self.src.push_str(&format!(
                 "
                    let span = tracing::span!(
                        tracing::Level::TRACE,
                        \"wit-bindgen export\",
-                       module = \"{}\",
+                       module = \"{ns}\",
                        function = \"{}\",
                    );
                    let _enter = span.enter();
                ",
-                ns.unwrap_or("default"),
                 func.name,
             ));
         }
@@ -1466,17 +1587,26 @@ impl<'a> RustGenerator<'a> for InterfaceGenerator<'a> {
     }
 
     fn path_to_interface(&self, interface: InterfaceId) -> Option<String> {
-        match self.current_interface {
-            Some(id) if id == interface => None,
-            _ => {
-                let InterfaceName { remapped, name } = &self.gen.interface_names[&interface];
-                Some(if self.current_interface.is_some() && !remapped {
-                    format!("super::{name}")
-                } else {
-                    name.clone()
-                })
+        let mut path_to_root = String::new();
+        if let Some((cur, key, is_export)) = self.current_interface {
+            if cur == interface {
+                return None;
+            }
+            match key {
+                WorldKey::Name(_) => {
+                    path_to_root.push_str("super::");
+                }
+                WorldKey::Interface(_) => {
+                    path_to_root.push_str("super::super::super::");
+                }
+            }
+            if is_export {
+                path_to_root.push_str("super::");
             }
         }
+        let InterfaceName { path, .. } = &self.gen.interface_names[&interface];
+        path_to_root.push_str(path);
+        Some(path_to_root)
     }
 
     fn push_str(&mut self, s: &str) {
diff --git a/supply-chain/imports.lock b/supply-chain/imports.lock
index ea3707aac..f017f8768 100644
--- a/supply-chain/imports.lock
+++ b/supply-chain/imports.lock
@@ -64,6 +64,13 @@ user-id = 1
 user-login = "alexcrichton"
 user-name = "Alex Crichton"
 
+[[publisher.wasm-encoder]]
+version = "0.29.0"
+when = "2023-05-26"
+user-id = 1
+user-login = "alexcrichton"
+user-name = "Alex Crichton"
+
 [[publisher.wasm-metadata]]
 version = "0.5.0"
 when = "2023-04-27"
@@ -78,6 +85,13 @@ user-id = 1
 user-login = "alexcrichton"
 user-name = "Alex Crichton"
 
+[[publisher.wasm-metadata]]
+version = "0.8.0"
+when = "2023-05-26"
+user-id = 1
+user-login = "alexcrichton"
+user-name = "Alex Crichton"
+
 [[publisher.wasm-mutate]]
 version = "0.2.25"
 when = "2023-05-15"
@@ -85,6 +99,13 @@ user-id = 1
 user-login = "alexcrichton"
 user-name = "Alex Crichton"
 
+[[publisher.wasm-mutate]]
+version = "0.2.27"
+when = "2023-05-26"
+user-id = 1
+user-login = "alexcrichton"
+user-name = "Alex Crichton"
+
 [[publisher.wasm-smith]]
 version = "0.12.8"
 when = "2023-05-15"
@@ -92,6 +113,13 @@ user-id = 1
 user-login = "alexcrichton"
 user-name = "Alex Crichton"
 
+[[publisher.wasm-smith]]
+version = "0.12.10"
+when = "2023-05-26"
+user-id = 1
+user-login = "alexcrichton"
+user-name = "Alex Crichton"
+
 [[publisher.wasmparser]]
 version = "0.104.0"
 when = "2023-04-27"
@@ -106,72 +134,72 @@ user-id = 1
 user-login = "alexcrichton"
 user-name = "Alex Crichton"
 
-[[publisher.wasmprinter]]
-version = "0.2.57"
-when = "2023-05-15"
+[[publisher.wasmparser]]
+version = "0.107.0"
+when = "2023-05-26"
 user-id = 1
 user-login = "alexcrichton"
 user-name = "Alex Crichton"
 
-[[publisher.wast]]
-version = "58.0.0"
+[[publisher.wasmprinter]]
+version = "0.2.57"
 when = "2023-05-15"
 user-id = 1
 user-login = "alexcrichton"
 user-name = "Alex Crichton"
 
-[[publisher.wat]]
-version = "1.0.64"
-when = "2023-05-15"
+[[publisher.wasmprinter]]
+version = "0.2.59"
+when = "2023-05-26"
 user-id = 1
 user-login = "alexcrichton"
 user-name = "Alex Crichton"
 
-[[publisher.wit-bindgen]]
-version = "0.6.0"
-when = "2023-04-27"
+[[publisher.wast]]
+version = "58.0.0"
+when = "2023-05-15"
 user-id = 1
 user-login = "alexcrichton"
 user-name = "Alex Crichton"
 
-[[publisher.wit-bindgen-core]]
-version = "0.6.0"
-when = "2023-04-27"
+[[publisher.wast]]
+version = "60.0.0"
+when = "2023-05-26"
 user-id = 1
 user-login = "alexcrichton"
 user-name = "Alex Crichton"
 
-[[publisher.wit-bindgen-rust]]
-version = "0.6.0"
-when = "2023-04-27"
+[[publisher.wat]]
+version = "1.0.64"
+when = "2023-05-15"
 user-id = 1
 user-login = "alexcrichton"
 user-name = "Alex Crichton"
 
-[[publisher.wit-bindgen-rust-lib]]
-version = "0.6.0"
-when = "2023-04-27"
+[[publisher.wat]]
+version = "1.0.66"
+when = "2023-05-26"
 user-id = 1
 user-login = "alexcrichton"
 user-name = "Alex Crichton"
 
-[[publisher.wit-bindgen-rust-macro]]
-version = "0.6.0"
+[[publisher.wit-component]]
+version = "0.8.2"
 when = "2023-04-27"
 user-id = 1
 user-login = "alexcrichton"
 user-name = "Alex Crichton"
 
 [[publisher.wit-component]]
-version = "0.8.2"
-when = "2023-04-27"
+version = "0.9.0"
+when = "2023-05-16"
 user-id = 1
 user-login = "alexcrichton"
 user-name = "Alex Crichton"
 
 [[publisher.wit-component]]
-version = "0.9.0"
-when = "2023-05-16"
+version = "0.11.0"
+when = "2023-05-26"
 user-id = 1
 user-login = "alexcrichton"
 user-name = "Alex Crichton"
@@ -183,6 +211,13 @@ user-id = 1
 user-login = "alexcrichton"
 user-name = "Alex Crichton"
 
+[[publisher.wit-parser]]
+version = "0.8.0"
+when = "2023-05-26"
+user-id = 1
+user-login = "alexcrichton"
+user-name = "Alex Crichton"
+
 [[audits.embark-studios.audits.anyhow]]
 who = "Johan Andersson <opensource@embark-studios.com>"
 criteria = "safe-to-deploy"


Test patch:
diff --git a/crates/component-macro/tests/codegen.rs b/crates/component-macro/tests/codegen.rs
index ac3953402..616f3253c 100644
--- a/crates/component-macro/tests/codegen.rs
+++ b/crates/component-macro/tests/codegen.rs
@@ -4,9 +4,6 @@ macro_rules! gentest {
             mod sugar {
                 wasmtime::component::bindgen!(in $path);
             }
-            mod normal {
-                wasmtime::component::bindgen!($name in $path);
-            }
             mod async_ {
                 wasmtime::component::bindgen!({
                     path: $path,
@@ -16,15 +13,12 @@ macro_rules! gentest {
             mod tracing {
                 wasmtime::component::bindgen!({
                     path: $path,
-                    world: $name,
                     tracing: true,
                     duplicate_if_necessary: true,
                 });
             }
         }
-        // ...
     };
-
 }
 
 component_macro_test_helpers::foreach!(gentest);
diff --git a/crates/component-macro/tests/codegen/char.wit b/crates/component-macro/tests/codegen/char.wit
index 01b20f700..b49947b38 100644
--- a/crates/component-macro/tests/codegen/char.wit
+++ b/crates/component-macro/tests/codegen/char.wit
@@ -1,3 +1,5 @@
+package foo:foo
+
 interface chars {
   /// A function that accepts a character
   take-char: func(x: char)
@@ -5,7 +7,7 @@ interface chars {
   return-char: func() -> char
 }
 
-default world the-world {
-  import imports: self.chars
-  export exports: self.chars
+world the-world {
+  import chars
+  export chars
 }
diff --git a/crates/component-macro/tests/codegen/conventions.wit b/crates/component-macro/tests/codegen/conventions.wit
index 2c5645c66..a96b5afd3 100644
--- a/crates/component-macro/tests/codegen/conventions.wit
+++ b/crates/component-macro/tests/codegen/conventions.wit
@@ -1,4 +1,5 @@
 // hello 🐱 world
+package foo:foo
 
 interface conventions {
   kebab-case: func()
@@ -32,7 +33,7 @@ interface conventions {
   %bool: func()
 }
 
-default world the-world {
-  import imports: self.conventions
-  export exports: self.conventions
+world the-world {
+  import conventions
+  export conventions
 }
diff --git a/crates/component-macro/tests/codegen/direct-import.wit b/crates/component-macro/tests/codegen/direct-import.wit
index d2b612d6d..67d252a4a 100644
--- a/crates/component-macro/tests/codegen/direct-import.wit
+++ b/crates/component-macro/tests/codegen/direct-import.wit
@@ -1,3 +1,5 @@
-default world foo {
+package foo:foo
+
+world foo {
   import foo: func()
 }
diff --git a/crates/component-macro/tests/codegen/empty.wit b/crates/component-macro/tests/codegen/empty.wit
index 1f99081f5..b720c27d6 100644
--- a/crates/component-macro/tests/codegen/empty.wit
+++ b/crates/component-macro/tests/codegen/empty.wit
@@ -1,1 +1,2 @@
-default world empty {}
+package foo:foo
+world empty {}
diff --git a/crates/component-macro/tests/codegen/flags.wit b/crates/component-macro/tests/codegen/flags.wit
index b5a2fa2d1..8c9c14371 100644
--- a/crates/component-macro/tests/codegen/flags.wit
+++ b/crates/component-macro/tests/codegen/flags.wit
@@ -1,3 +1,5 @@
+package foo:foo
+
 interface flegs {
   flags flag1 {
     b0,
@@ -47,7 +49,7 @@ interface flegs {
   roundtrip-flag64: func(x: flag64) -> flag64
 }
 
-default world the-flags {
-  import import-flags: self.flegs
-  export export-flags: self.flegs
+world the-flags {
+  import flegs
+  export flegs
 }
diff --git a/crates/component-macro/tests/codegen/floats.wit b/crates/component-macro/tests/codegen/floats.wit
index 4a0c67ce2..6cd720a8d 100644
--- a/crates/component-macro/tests/codegen/floats.wit
+++ b/crates/component-macro/tests/codegen/floats.wit
@@ -1,3 +1,5 @@
+package foo:foo
+
 interface floats {
   float32-param: func(x: float32)
   float64-param: func(x: float64)
@@ -5,7 +7,7 @@ interface floats {
   float64-result: func() -> float64
 }
 
-default world the-world {
-  import imports: self.floats
-  export exports: self.floats
+world the-world {
+  import floats
+  export floats
 }
diff --git a/crates/component-macro/tests/codegen/function-new.wit b/crates/component-macro/tests/codegen/function-new.wit
index fed79c663..2f4e40756 100644
--- a/crates/component-macro/tests/codegen/function-new.wit
+++ b/crates/component-macro/tests/codegen/function-new.wit
@@ -1,3 +1,4 @@
-default world foo {
+package foo:foo
+world foo {
   export new: func()
 }
diff --git a/crates/component-macro/tests/codegen/integers.wit b/crates/component-macro/tests/codegen/integers.wit
index bfad27288..2f5866bb2 100644
--- a/crates/component-macro/tests/codegen/integers.wit
+++ b/crates/component-macro/tests/codegen/integers.wit
@@ -1,3 +1,5 @@
+package foo:foo
+
 interface integers {
   a1: func(x: u8)
   a2: func(x: s8)
@@ -32,7 +34,7 @@ interface integers {
   pair-ret: func() -> tuple<s64, u8>
 }
 
-default world the-world {
-  import imports: self.integers
-  export exports: self.integers
+world the-world {
+  import integers
+  export integers
 }
diff --git a/crates/component-macro/tests/codegen/lists.wit b/crates/component-macro/tests/codegen/lists.wit
index 19b946068..256a1cdf8 100644
--- a/crates/component-macro/tests/codegen/lists.wit
+++ b/crates/component-macro/tests/codegen/lists.wit
@@ -1,3 +1,5 @@
+package foo:foo
+
 interface lists {
   list-u8-param: func(x: list<u8>)
   list-u16-param: func(x: list<u16>)
@@ -77,7 +79,7 @@ interface lists {
   load-store-everything: func(a: load-store-all-sizes) -> load-store-all-sizes
 }
 
-default world the-lists {
-  import import-lists: self.lists
-  export export-lists: self.lists
+world the-lists {
+  import lists
+  export lists
 }
diff --git a/crates/component-macro/tests/codegen/many-arguments.wit b/crates/component-macro/tests/codegen/many-arguments.wit
index a5b67b218..cbfc12314 100644
--- a/crates/component-macro/tests/codegen/many-arguments.wit
+++ b/crates/component-macro/tests/codegen/many-arguments.wit
@@ -1,3 +1,5 @@
+package foo:foo
+
 interface manyarg {
   many-args: func(
     a1: u64,
@@ -44,7 +46,7 @@ interface manyarg {
   big-argument: func(x: big-struct)
 }
 
-default world the-world {
-  import imports: self.manyarg
-  export exports: self.manyarg
+world the-world {
+  import manyarg
+  export manyarg
 }
diff --git a/crates/component-macro/tests/codegen/multi-return.wit b/crates/component-macro/tests/codegen/multi-return.wit
index 716e77a6c..69951b2c3 100644
--- a/crates/component-macro/tests/codegen/multi-return.wit
+++ b/crates/component-macro/tests/codegen/multi-return.wit
@@ -1,3 +1,5 @@
+package foo:foo
+
 interface multi-return {
   mra: func()
   mrb: func() -> ()
@@ -6,7 +8,7 @@ interface multi-return {
   mre: func() -> (a: u32, b: float32)
 }
 
-default world the-world {
-  import imports: self.multi-return
-  export exports: self.multi-return
+world the-world {
+  import multi-return
+  export multi-return
 }
diff --git a/crates/component-macro/tests/codegen/records.wit b/crates/component-macro/tests/codegen/records.wit
index 39d5e8169..f51bb8f28 100644
--- a/crates/component-macro/tests/codegen/records.wit
+++ b/crates/component-macro/tests/codegen/records.wit
@@ -1,3 +1,5 @@
+package foo:foo
+
 interface records {
   tuple-arg: func(x: tuple<char, u32>)
   tuple-result: func() -> tuple<char, u32>
@@ -53,7 +55,7 @@ interface records {
   typedef-inout: func(e: tuple-typedef2) -> s32
 }
 
-default world the-world {
-  import imports: self.records
-  export exports: self.records
+world the-world {
+  import records
+  export records
 }
diff --git a/crates/component-macro/tests/codegen/rename.wit b/crates/component-macro/tests/codegen/rename.wit
index d60d4f6f9..8bfc7f368 100644
--- a/crates/component-macro/tests/codegen/rename.wit
+++ b/crates/component-macro/tests/codegen/rename.wit
@@ -1,5 +1,7 @@
+package foo:foo
+
 interface red {
-  use self.green.{thing}
+  use green.{thing}
 
   foo: func() -> thing
 }
@@ -8,7 +10,7 @@ interface green {
   type thing = s32
 }
 
-default world neptune {
-  import blue: self.red
-  import orange: self.green
+world neptune {
+  import red
+  import green
 }
diff --git a/crates/component-macro/tests/codegen/share-types.wit b/crates/component-macro/tests/codegen/share-types.wit
index 106ee7093..8d36d1b0a 100644
--- a/crates/component-macro/tests/codegen/share-types.wit
+++ b/crates/component-macro/tests/codegen/share-types.wit
@@ -1,3 +1,5 @@
+package foo:foo
+
 interface http-types{
   record request {
     method: string
@@ -7,13 +9,13 @@ interface http-types{
   }
 }
 
-default world http-interface {
+world http-interface {
   export http-handler: interface {
-    use self.http-types.{request,response}
+    use http-types.{request,response}
     handle-request: func(request: request) -> response
   }
   import http-fetch: interface {
-    use self.http-types.{request,response}
+    use http-types.{request,response}
     fetch-request: func(request: request) -> response
   }
 }
diff --git a/crates/component-macro/tests/codegen/simple-functions.wit b/crates/component-macro/tests/codegen/simple-functions.wit
index cdb118379..2593d199e 100644
--- a/crates/component-macro/tests/codegen/simple-functions.wit
+++ b/crates/component-macro/tests/codegen/simple-functions.wit
@@ -1,3 +1,5 @@
+package foo:foo
+
 interface simple {
   f1: func()
   f2: func(a: u32)
@@ -9,7 +11,7 @@ interface simple {
   f6: func(a: u32, b: u32, c: u32) -> tuple<u32, u32, u32>
 }
 
-default world the-world {
-  import imports: self.simple
-  export exports: self.simple
+world the-world {
+  import simple
+  export simple
 }
diff --git a/crates/component-macro/tests/codegen/simple-lists.wit b/crates/component-macro/tests/codegen/simple-lists.wit
index 885cdeb74..8e082b6e3 100644
--- a/crates/component-macro/tests/codegen/simple-lists.wit
+++ b/crates/component-macro/tests/codegen/simple-lists.wit
@@ -1,3 +1,5 @@
+package foo:foo
+
 interface simple-lists {
   simple-list1: func(l: list<u32>)
   simple-list2: func() -> list<u32>
@@ -5,7 +7,7 @@ interface simple-lists {
   simple-list4: func(l: list<list<u32>>) -> list<list<u32>>
 }
 
-default world my-world {
-  import imports: self.simple-lists
-  export exports: self.simple-lists
+world my-world {
+  import simple-lists
+  export simple-lists
 }
diff --git a/crates/component-macro/tests/codegen/simple-wasi.wit b/crates/component-macro/tests/codegen/simple-wasi.wit
index 02c47dc9b..60192473d 100644
--- a/crates/component-macro/tests/codegen/simple-wasi.wit
+++ b/crates/component-macro/tests/codegen/simple-wasi.wit
@@ -1,3 +1,5 @@
+package foo:foo
+
 interface wasi-filesystem {
   record descriptor-stat {
   }
@@ -15,7 +17,7 @@ interface wall-clock {
   }
 }
 
-default world wasi {
-  import wasi-filesystem: self.wasi-filesystem
-  import wall-clock: self.wall-clock
+world wasi {
+  import wasi-filesystem
+  import wall-clock
 }
diff --git a/crates/component-macro/tests/codegen/small-anonymous.wit b/crates/component-macro/tests/codegen/small-anonymous.wit
index 964360913..ad9c67287 100644
--- a/crates/component-macro/tests/codegen/small-anonymous.wit
+++ b/crates/component-macro/tests/codegen/small-anonymous.wit
@@ -1,3 +1,5 @@
+package foo:foo
+
 interface anon {
   enum error {
     success,
@@ -7,7 +9,7 @@ interface anon {
   option-test: func() -> result<option<string>, error>
 }
 
-default world the-world {
-  import imports: self.anon
-  export exports: self.anon
+world the-world {
+  import anon
+  export anon
 }
diff --git a/crates/component-macro/tests/codegen/smoke-default.wit b/crates/component-macro/tests/codegen/smoke-default.wit
index 0d2693590..90be0b1e3 100644
--- a/crates/component-macro/tests/codegen/smoke-default.wit
+++ b/crates/component-macro/tests/codegen/smoke-default.wit
@@ -1,3 +1,5 @@
-default world the-world {
+package foo:foo
+
+world the-world {
   export y: func()
 }
diff --git a/crates/component-macro/tests/codegen/smoke-export.wit b/crates/component-macro/tests/codegen/smoke-export.wit
index cefdc1982..983f1c350 100644
--- a/crates/component-macro/tests/codegen/smoke-export.wit
+++ b/crates/component-macro/tests/codegen/smoke-export.wit
@@ -1,4 +1,6 @@
-default world the-world {
+package foo:foo
+
+world the-world {
   export the-name: interface {
     y: func()
   }
diff --git a/crates/component-macro/tests/codegen/smoke.wit b/crates/component-macro/tests/codegen/smoke.wit
index 6d8e80cce..0476bd988 100644
--- a/crates/component-macro/tests/codegen/smoke.wit
+++ b/crates/component-macro/tests/codegen/smoke.wit
@@ -1,4 +1,6 @@
-default world the-world {
+package foo:foo
+
+world the-world {
   import imports: interface {
     y: func()
   }
diff --git a/crates/component-macro/tests/codegen/strings.wit b/crates/component-macro/tests/codegen/strings.wit
index 7fc188552..650300acf 100644
--- a/crates/component-macro/tests/codegen/strings.wit
+++ b/crates/component-macro/tests/codegen/strings.wit
@@ -1,10 +1,12 @@
+package foo:foo
+
 interface strings {
   a: func(x: string)
   b: func() -> string
   c: func(a: string, b: string) -> string
 }
 
-default world the-world {
-  import imports: self.strings
-  export exports: self.strings
+world the-world {
+  import strings
+  export strings
 }
diff --git a/crates/component-macro/tests/codegen/unions.wit b/crates/component-macro/tests/codegen/unions.wit
index 07e0f380a..252f513f2 100644
--- a/crates/component-macro/tests/codegen/unions.wit
+++ b/crates/component-macro/tests/codegen/unions.wit
@@ -1,3 +1,5 @@
+package foo:foo
+
 interface unions {
   /// A union of all of the integral types
   union all-integers {
@@ -58,7 +60,7 @@ interface unions {
   identify-distinguishable-num: func(num: distinguishable-num) -> u8
 }
 
-default world the-unions {
-  import import-unions: self.unions
-  export export-unions: self.unions
+world the-unions {
+  import unions
+  export unions
 }
diff --git a/crates/component-macro/tests/codegen/use-paths.wit b/crates/component-macro/tests/codegen/use-paths.wit
index 1e877379c..dab6646af 100644
--- a/crates/component-macro/tests/codegen/use-paths.wit
+++ b/crates/component-macro/tests/codegen/use-paths.wit
@@ -1,3 +1,5 @@
+package foo:foo
+
 interface a {
   record foo {}
 
@@ -5,22 +7,22 @@ interface a {
 }
 
 interface b {
-  use self.a.{foo}
+  use a.{foo}
 
   a: func() -> foo
 }
 
 interface c {
-  use self.b.{foo}
+  use b.{foo}
 
   a: func() -> foo
 }
 
-default world d {
-  import a: self.a
-  import b: self.b
+world d {
+  import a
+  import b
   import d: interface {
-    use self.c.{foo}
+    use c.{foo}
 
     b: func() -> foo
   }
diff --git a/crates/component-macro/tests/codegen/variants.wit b/crates/component-macro/tests/codegen/variants.wit
index 590675dcf..b6c47d896 100644
--- a/crates/component-macro/tests/codegen/variants.wit
+++ b/crates/component-macro/tests/codegen/variants.wit
@@ -1,3 +1,5 @@
+package foo:foo
+
 interface variants {
   enum e1 {
       a,
@@ -139,7 +141,7 @@ interface variants {
   return-named-result: func() -> (a: result<u8, my-errno>)
 }
 
-default world my-world {
-  import imports: self.variants
-  export exports: self.variants
+world my-world {
+  import variants
+  export variants
 }
diff --git a/crates/component-macro/tests/codegen/worlds-with-types.wit b/crates/component-macro/tests/codegen/worlds-with-types.wit
index 25db9036d..dc4cbddcb 100644
--- a/crates/component-macro/tests/codegen/worlds-with-types.wit
+++ b/crates/component-macro/tests/codegen/worlds-with-types.wit
@@ -1,9 +1,11 @@
+package foo:foo
+
 interface i {
   type t = u16
 }
 
-default world foo {
-  use self.i.{t as u}
+world foo {
+  use i.{t as u}
 
   type t = u32
 
diff --git a/crates/test-programs/Cargo.toml b/crates/test-programs/Cargo.toml
index 6e07ab9ea..37a97b40b 100644
--- a/crates/test-programs/Cargo.toml
+++ b/crates/test-programs/Cargo.toml
@@ -13,6 +13,7 @@ cargo_metadata = "0.15.3"
 wit-component = { workspace = true }
 heck = { workspace = true }
 
+
 [dev-dependencies]
 anyhow = { workspace = true }
 tempfile = { workspace = true }
diff --git a/crates/test-programs/build.rs b/crates/test-programs/build.rs
index e36db9162..e96ed83e3 100644
--- a/crates/test-programs/build.rs
+++ b/crates/test-programs/build.rs
@@ -7,6 +7,11 @@ use std::path::PathBuf;
 use std::process::Command;
 use wit_component::ComponentEncoder;
 
+// NB: this is set to `false` when a breaking change to WIT is made since the
+// wasi-http WIT is currently a submodule and can't be updated atomically with
+// the rest of Wasmtime.
+const BUILD_WASI_HTTP_TESTS: bool = false;
+
 fn main() {
     #[cfg(feature = "test_programs")]
     build_and_generate_tests();
@@ -23,9 +28,13 @@ fn build_and_generate_tests() {
     );
 
     println!("cargo:rerun-if-changed=./wasi-tests");
-    println!("cargo:rerun-if-changed=./wasi-http-tests");
     println!("cargo:rerun-if-changed=./command-tests");
     println!("cargo:rerun-if-changed=./reactor-tests");
+    if BUILD_WASI_HTTP_TESTS {
+        println!("cargo:rerun-if-changed=./wasi-http-tests");
+    } else {
+        println!("cargo:rustc-cfg=skip_wasi_http_tests");
+    }
 
     // Build the test programs:
     let mut cmd = Command::new("rustup");
@@ -35,12 +44,14 @@ fn build_and_generate_tests() {
         .arg("build")
         .arg("--target=wasm32-wasi")
         .arg("--package=wasi-tests")
-        .arg("--package=wasi-http-tests")
         .arg("--package=command-tests")
         .arg("--package=reactor-tests")
         .env("CARGO_TARGET_DIR", &out_dir)
         .env("CARGO_PROFILE_DEV_DEBUG", "1")
         .env_remove("CARGO_ENCODED_RUSTFLAGS");
+    if BUILD_WASI_HTTP_TESTS {
+        cmd.arg("--package=wasi-http-tests");
+    }
     let status = cmd.status().unwrap();
     assert!(status.success());
 
@@ -49,11 +60,13 @@ fn build_and_generate_tests() {
     modules_rs(&meta, "wasi-tests", "bin", &out_dir);
     components_rs(&meta, "wasi-tests", "bin", &command_adapter, &out_dir);
 
-    modules_rs(&meta, "wasi-http-tests", "bin", &out_dir);
-    // FIXME this is broken at the moment because guest bindgen is embedding the proxy world type,
-    // so wit-component expects the module to contain the proxy's exports. we need a different
-    // world to pass guest bindgen that is just "a command that also can do outbound http"
-    //components_rs(&meta, "wasi-http-tests", "bin", &command_adapter, &out_dir);
+    if BUILD_WASI_HTTP_TESTS {
+        modules_rs(&meta, "wasi-http-tests", "bin", &out_dir);
+        // FIXME this is broken at the moment because guest bindgen is embedding the proxy world type,
+        // so wit-component expects the module to contain the proxy's exports. we need a different
+        // world to pass guest bindgen that is just "a command that also can do outbound http"
+        //components_rs(&meta, "wasi-http-tests", "bin", &command_adapter, &out_dir);
+    }
 
     components_rs(&meta, "command-tests", "bin", &command_adapter, &out_dir);
     components_rs(&meta, "reactor-tests", "cdylib", &reactor_adapter, &out_dir);
diff --git a/crates/test-programs/reactor-tests/src/lib.rs b/crates/test-programs/reactor-tests/src/lib.rs
index c38640ac0..ff1c0cab7 100644
--- a/crates/test-programs/reactor-tests/src/lib.rs
+++ b/crates/test-programs/reactor-tests/src/lib.rs
@@ -1,4 +1,4 @@
-wit_bindgen::generate!("test-reactor");
+wit_bindgen::generate!("test-reactor" in "../../wasi/wit");
 
 export_test_reactor!(T);
 
@@ -26,12 +26,12 @@ impl TestReactor for T {
     fn write_strings_to(o: OutputStream) -> Result<(), ()> {
         unsafe {
             for s in STATE.iter() {
-                streams::write(o, s.as_bytes()).map_err(|_| ())?;
+                wasi::io::streams::write(o, s.as_bytes()).map_err(|_| ())?;
             }
             Ok(())
         }
     }
-    fn pass_an_imported_record(stat: filesystem::DescriptorStat) -> String {
+    fn pass_an_imported_record(stat: wasi::filesystem::filesystem::DescriptorStat) -> String {
         format!("{stat:?}")
     }
 }
diff --git a/crates/test-programs/reactor-tests/wit/deps.lock b/crates/test-programs/reactor-tests/wit/deps.lock
deleted file mode 100644
index bfa0b9d4f..000000000
--- a/crates/test-programs/reactor-tests/wit/deps.lock
+++ /dev/null
@@ -1,41 +0,0 @@
-[clocks]
-sha256 = "16155da02fdba4a51515b44dbd1c65e0909bb8c4d383bd32875c777044ce5389"
-sha512 = "30efd2697885954f3846322adf94f28a28f958595708407696ef66e8fe5bb62c79525e6f13ec469476cba8f2a12d3d9aef8250b1fe04c90a28542d3245db11f2"
-
-[filesystem]
-sha256 = "a3f57790dfd6af70758df33df82aa064f915eb795b71a190f272f10da9cfc9df"
-sha512 = "2b0059ffae0a4b1ce3bd8d489a40d08c1faa229bf1bb4cc8df0a98e0fd13d4694742117b2bc609d7fb75db1ed4aa148d3af7beca6a84866d87d65a1769b1d988"
-
-[http]
-sha256 = "b6a245b8f37f3be93650c1a8ae41c01923f3b7303bbf2d016d8d03a1c92b3c10"
-sha512 = "e2e0612213bb1272153b3858b13110a7fee0d89dc97d0021ab5ccccc8822ccc1f1629c8fa8dc582862411b2517ef3f79e7e51986c946654bf6ddd3f390cf36f2"
-
-[io]
-sha256 = "87d8bf336f37184edc9290af9a14f7cac38c8fe087a786e66d08d1a94e48d186"
-sha512 = "cdb5b35860c46c637ad37d784dd17f6023cf1c7c689d37973ec7c4094718baee4a16864e64622173b5578eed3950ad73211d9fe48a5b61b951809fdd9242b607"
-
-[logging]
-sha256 = "8c32c7f893c938e0b76cd42e3de97e268dfe8fd0e7525d1f42b7ad10a88b00bb"
-sha512 = "e9ce2adf02bb518c179a40b7d7af84bf44b99b2098609a897a114fb5af24946992dd7bd08da02c60d2768963f94414a16165f11343ec053a44b9e586058c812a"
-
-[poll]
-sha256 = "9f2e6b5ea1a017575f96a3c415c737fe31513b043d9b47aefeb21f6c27ab8425"
-sha512 = "f65965395742a0290fd9e4e55408c2b5ce3a4eae0ee22be1ff012e3db75910110da21c5f0a61083e043b4c510967a0a73ff4491ae9719e9158543f512dbeea5f"
-
-[preview]
-path = "../../../wit"
-sha256 = "007d4902193faef77b2df60714a8dfe8ec243e030c1ce61fb11c52788e3a5fe0"
-sha512 = "bd06e8338e7fad0fc2e56ae01c5b184282c66ca79d2040eaec5a11efb14a4002b2a6234baaf354aff3cd57dc99835e4979eb71cdbd5d12800ea289d9a13252f2"
-deps = ["clocks", "filesystem", "http", "io", "logging", "poll", "random", "sockets", "wasi-cli-base"]
-
-[random]
-sha256 = "19d57f2262530016ec2b32991db3d8b6705b3a0bc5a7b6ae8fff3bcef0cf1088"
-sha512 = "f9eba7dfd858d1edcaa868ce636f69545323bf010c3b0d4a2a1b23584d8027240c592d13e91882617e70a4dbf290754a8697724b5633147d11fa3db7869a2afe"
-
-[sockets]
-sha256 = "d5a51604d53eec88d2735356ce7089a0eeb06886262e7ad2fc74be6b4dd943b2"
-sha512 = "99bd86c0c59174bc9dafc559ca7dbab1aa9ed04a9b54ae3f7bb2d974b3a97bae8846acf1d77232edecda0aef5b23b9e4010d53ebf4a1d04292581078763530b7"
-
-[wasi-cli-base]
-sha256 = "a0beee69392d2b55baff0b5f2285f50f717473b1369bdb3fbbfbefbaa3bd6c86"
-sha512 = "d80eada98646bfeec1066437f1a4f69d67d117f38407f35c48d8b31667c171656059c5abf638c5b31169119ef5fa73bbf199933ac198f815f58281f124cb4f8d"
diff --git a/crates/test-programs/reactor-tests/wit/deps.toml b/crates/test-programs/reactor-tests/wit/deps.toml
deleted file mode 100644
index c90a145d0..000000000
--- a/crates/test-programs/reactor-tests/wit/deps.toml
+++ /dev/null
@@ -1,1 +0,0 @@
-preview = "../../../wit"
diff --git a/crates/test-programs/reactor-tests/wit/deps/clocks/monotonic-clock.wit b/crates/test-programs/reactor-tests/wit/deps/clocks/monotonic-clock.wit
deleted file mode 100644
index 42e2981f5..000000000
--- a/crates/test-programs/reactor-tests/wit/deps/clocks/monotonic-clock.wit
+++ /dev/null
@@ -1,32 +0,0 @@
-/// WASI Monotonic Clock is a clock API intended to let users measure elapsed
-/// time.
-///
-/// It is intended to be portable at least between Unix-family platforms and
-/// Windows.
-///
-/// A monotonic clock is a clock which has an unspecified initial value, and
-/// successive reads of the clock will produce non-decreasing values.
-///
-/// It is intended for measuring elapsed time.
-default interface monotonic-clock {
-    use poll.poll.{pollable}
-
-    /// A timestamp in nanoseconds.
-    type instant = u64
-
-    /// Read the current value of the clock.
-    ///
-    /// The clock is monotonic, therefore calling this function repeatedly will
-    /// produce a sequence of non-decreasing values.
-    now: func() -> instant
-
-    /// Query the resolution of the clock.
-    resolution: func() -> instant
-
-    /// Create a `pollable` which will resolve once the specified time has been
-    /// reached.
-    subscribe: func(
-        when: instant,
-        absolute: bool
-    ) -> pollable
-}
diff --git a/crates/test-programs/reactor-tests/wit/deps/clocks/timezone.wit b/crates/test-programs/reactor-tests/wit/deps/clocks/timezone.wit
deleted file mode 100644
index 63f99cc40..000000000
--- a/crates/test-programs/reactor-tests/wit/deps/clocks/timezone.wit
+++ /dev/null
@@ -1,61 +0,0 @@
-default interface timezone {
-    use pkg.wall-clock.{datetime}
-
-    /// A timezone.
-    ///
-    /// In timezones that recognize daylight saving time, also known as daylight
-    /// time and summer time, the information returned from the functions varies
-    /// over time to reflect these adjustments.
-    ///
-    /// This [represents a resource](https://github.com/WebAssembly/WASI/blob/main/docs/WitInWasi.md#Resources).
-    type timezone = u32
-
-    /// Return information needed to display the given `datetime`. This includes
-    /// the UTC offset, the time zone name, and a flag indicating whether
-    /// daylight saving time is active.
-    ///
-    /// If the timezone cannot be determined for the given `datetime`, return a
-    /// `timezone-display` for `UTC` with a `utc-offset` of 0 and no daylight
-    /// saving time.
-    display: func(this: timezone, when: datetime) -> timezone-display
-
-    /// The same as `display`, but only return the UTC offset.
-    utc-offset: func(this: timezone, when: datetime) -> s32
-
-    /// Dispose of the specified input-stream, after which it may no longer
-    /// be used.
-    drop-timezone: func(this: timezone)
-
-    /// Information useful for displaying the timezone of a specific `datetime`.
-    ///
-    /// This information may vary within a single `timezone` to reflect daylight
-    /// saving time adjustments.
-    record timezone-display {
-        /// The number of seconds difference between UTC time and the local
-        /// time of the timezone.
-        ///
-        /// The returned value will always be less than 86400 which is the
-        /// number of seconds in a day (24*60*60).
-        ///
-        /// In implementations that do not expose an actual time zone, this
-        /// should return 0.
-        utc-offset: s32,
-
-        /// The abbreviated name of the timezone to display to a user. The name
-        /// `UTC` indicates Coordinated Universal Time. Otherwise, this should
-        /// reference local standards for the name of the time zone.
-        ///
-        /// In implementations that do not expose an actual time zone, this
-        /// should be the string `UTC`.
-        ///
-        /// In time zones that do not have an applicable name, a formatted
-        /// representation of the UTC offset may be returned, such as `-04:00`.
-        name: string,
-
-        /// Whether daylight saving time is active.
-        ///
-        /// In implementations that do not expose an actual time zone, this
-        /// should return false.
-        in-daylight-saving-time: bool,
-    }
-}
diff --git a/crates/test-programs/reactor-tests/wit/deps/clocks/wall-clock.wit b/crates/test-programs/reactor-tests/wit/deps/clocks/wall-clock.wit
deleted file mode 100644
index 89c5a75da..000000000
--- a/crates/test-programs/reactor-tests/wit/deps/clocks/wall-clock.wit
+++ /dev/null
@@ -1,41 +0,0 @@
-/// WASI Wall Clock is a clock API intended to let users query the current
-/// time. The name "wall" makes an analogy to a "clock on the wall", which
-/// is not necessarily monotonic as it may be reset.
-///
-/// It is intended to be portable at least between Unix-family platforms and
-/// Windows.
-///
-/// A wall clock is a clock which measures the date and time according to
-/// some external reference.
-///
-/// External references may be reset, so this clock is not necessarily
-/// monotonic, making it unsuitable for measuring elapsed time.
-///
-/// It is intended for reporting the current date and time for humans.
-default interface wall-clock {
-    /// A time and date in seconds plus nanoseconds.
-    record datetime {
-        seconds: u64,
-        nanoseconds: u32,
-    }
-
-    /// Read the current value of the clock.
-    ///
-    /// This clock is not monotonic, therefore calling this function repeatedly
-    /// will not necessarily produce a sequence of non-decreasing values.
-    ///
-    /// The returned timestamps represent the number of seconds since
-    /// 1970-01-01T00:00:00Z, also known as [POSIX's Seconds Since the Epoch],
-    /// also known as [Unix Time].
-    ///
-    /// The nanoseconds field of the output is always less than 1000000000.
-    ///
-    /// [POSIX's Seconds Since the Epoch]: https://pubs.opengroup.org/onlinepubs/9699919799/xrat/V4_xbd_chap04.html#tag_21_04_16
-    /// [Unix Time]: https://en.wikipedia.org/wiki/Unix_time
-    now: func() -> datetime
-
-    /// Query the resolution of the clock.
-    ///
-    /// The nanoseconds field of the output is always less than 1000000000.
-    resolution: func() -> datetime
-}
diff --git a/crates/test-programs/reactor-tests/wit/deps/io/streams.wit b/crates/test-programs/reactor-tests/wit/deps/io/streams.wit
deleted file mode 100644
index c1567fd4c..000000000
--- a/crates/test-programs/reactor-tests/wit/deps/io/streams.wit
+++ /dev/null
@@ -1,213 +0,0 @@
-/// WASI I/O is an I/O abstraction API which is currently focused on providing
-/// stream types.
-///
-/// In the future, the component model is expected to add built-in stream types;
-/// when it does, they are expected to subsume this API.
-default interface streams {
-    use poll.poll.{pollable}
-
-    /// An error type returned from a stream operation. Currently this
-    /// doesn't provide any additional information.
-    record stream-error {}
-
-    /// An input bytestream. In the future, this will be replaced by handle
-    /// types.
-    ///
-    /// This conceptually represents a `stream<u8, _>`. It's temporary
-    /// scaffolding until component-model's async features are ready.
-    ///
-    /// `input-stream`s are *non-blocking* to the extent practical on underlying
-    /// platforms. I/O operations always return promptly; if fewer bytes are
-    /// promptly available than requested, they return the number of bytes promptly
-    /// available, which could even be zero. To wait for data to be available,
-    /// use the `subscribe-to-input-stream` function to obtain a `pollable` which
-    /// can be polled for using `wasi_poll`.
-    ///
-    /// And at present, it is a `u32` instead of being an actual handle, until
-    /// the wit-bindgen implementation of handles and resources is ready.
-    ///
-    /// This [represents a resource](https://github.com/WebAssembly/WASI/blob/main/docs/WitInWasi.md#Resources).
-    type input-stream = u32
-
-    /// Read bytes from a stream.
-    ///
-    /// This function returns a list of bytes containing the data that was
-    /// read, along with a bool which, when true, indicates that the end of the
-    /// stream was reached. The returned list will contain up to `len` bytes; it
-    /// may return fewer than requested, but not more.
-    ///
-    /// Once a stream has reached the end, subsequent calls to read or
-    /// `skip` will always report end-of-stream rather than producing more
-    /// data.
-    ///
-    /// If `len` is 0, it represents a request to read 0 bytes, which should
-    /// always succeed, assuming the stream hasn't reached its end yet, and
-    /// return an empty list.
-    ///
-    /// The len here is a `u64`, but some callees may not be able to allocate
-    /// a buffer as large as that would imply.
-    /// FIXME: describe what happens if allocation fails.
-    read: func(
-        this: input-stream,
-        /// The maximum number of bytes to read
-        len: u64
-    ) -> result<tuple<list<u8>, bool>, stream-error>
-
-    /// Read bytes from a stream, with blocking.
-    ///
-    /// This is similar to `read`, except that it blocks until at least one
-    /// byte can be read.
-    blocking-read: func(
-        this: input-stream,
-        /// The maximum number of bytes to read
-        len: u64
-    ) -> result<tuple<list<u8>, bool>, stream-error>
-
-    /// Skip bytes from a stream.
-    ///
-    /// This is similar to the `read` function, but avoids copying the
-    /// bytes into the instance.
-    ///
-    /// Once a stream has reached the end, subsequent calls to read or
-    /// `skip` will always report end-of-stream rather than producing more
-    /// data.
-    ///
-    /// This function returns the number of bytes skipped, along with a bool
-    /// indicating whether the end of the stream was reached. The returned
-    /// value will be at most `len`; it may be less.
-    skip: func(
-        this: input-stream,
-        /// The maximum number of bytes to skip.
-        len: u64,
-    ) -> result<tuple<u64, bool>, stream-error>
-
-    /// Skip bytes from a stream, with blocking.
-    ///
-    /// This is similar to `skip`, except that it blocks until at least one
-    /// byte can be consumed.
-    blocking-skip: func(
-        this: input-stream,
-        /// The maximum number of bytes to skip.
-        len: u64,
-    ) -> result<tuple<u64, bool>, stream-error>
-
-    /// Create a `pollable` which will resolve once either the specified stream
-    /// has bytes available to read or the other end of the stream has been
-    /// closed.
-    subscribe-to-input-stream: func(this: input-stream) -> pollable
-
-    /// Dispose of the specified `input-stream`, after which it may no longer
-    /// be used.
-    drop-input-stream: func(this: input-stream)
-
-    /// An output bytestream. In the future, this will be replaced by handle
-    /// types.
-    ///
-    /// This conceptually represents a `stream<u8, _>`. It's temporary
-    /// scaffolding until component-model's async features are ready.
-    ///
-    /// `output-stream`s are *non-blocking* to the extent practical on
-    /// underlying platforms. Except where specified otherwise, I/O operations also
-    /// always return promptly, after the number of bytes that can be written
-    /// promptly, which could even be zero. To wait for the stream to be ready to
-    /// accept data, the `subscribe-to-output-stream` function to obtain a
-    /// `pollable` which can be polled for using `wasi_poll`.
-    ///
-    /// And at present, it is a `u32` instead of being an actual handle, until
-    /// the wit-bindgen implementation of handles and resources is ready.
-    ///
-    /// This [represents a resource](https://github.com/WebAssembly/WASI/blob/main/docs/WitInWasi.md#Resources).
-    type output-stream = u32
-
-    /// Write bytes to a stream.
-    ///
-    /// This function returns a `u64` indicating the number of bytes from
-    /// `buf` that were written; it may be less than the full list.
-    write: func(
-        this: output-stream,
-        /// Data to write
-        buf: list<u8>
-    ) -> result<u64, stream-error>
-
-    /// Write bytes to a stream, with blocking.
-    ///
-    /// This is similar to `write`, except that it blocks until at least one
-    /// byte can be written.
-    blocking-write: func(
-        this: output-stream,
-        /// Data to write
-        buf: list<u8>
-    ) -> result<u64, stream-error>
-
-    /// Write multiple zero bytes to a stream.
-    ///
-    /// This function returns a `u64` indicating the number of zero bytes
-    /// that were written; it may be less than `len`.
-    write-zeroes: func(
-        this: output-stream,
-        /// The number of zero bytes to write
-        len: u64
-    ) -> result<u64, stream-error>
-
-    /// Write multiple zero bytes to a stream, with blocking.
-    ///
-    /// This is similar to `write-zeroes`, except that it blocks until at least
-    /// one byte can be written.
-    blocking-write-zeroes: func(
-        this: output-stream,
-        /// The number of zero bytes to write
-        len: u64
-    ) -> result<u64, stream-error>
-
-    /// Read from one stream and write to another.
-    ///
-    /// This function returns the number of bytes transferred; it may be less
-    /// than `len`.
-    ///
-    /// Unlike other I/O functions, this function blocks until all the data
-    /// read from the input stream has been written to the output stream.
-    splice: func(
-        this: output-stream,
-        /// The stream to read from
-        src: input-stream,
-        /// The number of bytes to splice
-        len: u64,
-    ) -> result<tuple<u64, bool>, stream-error>
-
-    /// Read from one stream and write to another, with blocking.
-    ///
-    /// This is similar to `splice`, except that it blocks until at least
-    /// one byte can be read.
-    blocking-splice: func(
-        this: output-stream,
-        /// The stream to read from
-        src: input-stream,
-        /// The number of bytes to splice
-        len: u64,
-    ) -> result<tuple<u64, bool>, stream-error>
-
-    /// Forward the entire contents of an input stream to an output stream.
-    ///
-    /// This function repeatedly reads from the input stream and writes
-    /// the data to the output stream, until the end of the input stream
-    /// is reached, or an error is encountered.
-    ///
-    /// Unlike other I/O functions, this function blocks until the end
-    /// of the input stream is seen and all the data has been written to
-    /// the output stream.
-    ///
-    /// This function returns the number of bytes transferred.
-    forward: func(
-        this: output-stream,
-        /// The stream to read from
-        src: input-stream
-    ) -> result<u64, stream-error>
-
-    /// Create a `pollable` which will resolve once either the specified stream
-    /// is ready to accept bytes or the other end of the stream has been closed.
-    subscribe-to-output-stream: func(this: output-stream) -> pollable
-
-    /// Dispose of the specified `output-stream`, after which it may no longer
-    /// be used.
-    drop-output-stream: func(this: output-stream)
-}
diff --git a/crates/test-programs/reactor-tests/wit/deps/poll/poll.wit b/crates/test-programs/reactor-tests/wit/deps/poll/poll.wit
deleted file mode 100644
index 28f08e17d..000000000
--- a/crates/test-programs/reactor-tests/wit/deps/poll/poll.wit
+++ /dev/null
@@ -1,39 +0,0 @@
-/// A poll API intended to let users wait for I/O events on multiple handles
-/// at once.
-default interface poll {
-    /// A "pollable" handle.
-    ///
-    /// This is conceptually represents a `stream<_, _>`, or in other words,
-    /// a stream that one can wait on, repeatedly, but which does not itself
-    /// produce any data. It's temporary scaffolding until component-model's
-    /// async features are ready.
-    ///
-    /// And at present, it is a `u32` instead of being an actual handle, until
-    /// the wit-bindgen implementation of handles and resources is ready.
-    ///
-    /// `pollable` lifetimes are not automatically managed. Users must ensure
-    /// that they do not outlive the resource they reference.
-    ///
-    /// This [represents a resource](https://github.com/WebAssembly/WASI/blob/main/docs/WitInWasi.md#Resources).
-    type pollable = u32
-
-    /// Dispose of the specified `pollable`, after which it may no longer
-    /// be used.
-    drop-pollable: func(this: pollable)
-
-    /// Poll for completion on a set of pollables.
-    ///
-    /// The "oneoff" in the name refers to the fact that this function must do a
-    /// linear scan through the entire list of subscriptions, which may be
-    /// inefficient if the number is large and the same subscriptions are used
-    /// many times. In the future, this is expected to be obsoleted by the
-    /// component model async proposal, which will include a scalable waiting
-    /// facility.
-    ///
-    /// Note that the return type would ideally be `list<bool>`, but that would
-    /// be more difficult to polyfill given the current state of `wit-bindgen`.
-    /// See <https://github.com/bytecodealliance/preview2-prototyping/pull/11#issuecomment-1329873061>
-    /// for details.  For now, we use zero to mean "not ready" and non-zero to
-    /// mean "ready".
-    poll-oneoff: func(in: list<pollable>) -> list<u8>
-}
diff --git a/crates/test-programs/reactor-tests/wit/deps/wasi-cli-base/environment.wit b/crates/test-programs/reactor-tests/wit/deps/wasi-cli-base/environment.wit
deleted file mode 100644
index 876ea3a0c..000000000
--- a/crates/test-programs/reactor-tests/wit/deps/wasi-cli-base/environment.wit
+++ /dev/null
@@ -1,14 +0,0 @@
-default interface environment {
-  /// Get the POSIX-style environment variables.
-  ///
-  /// Each environment variable is provided as a pair of string variable names
-  /// and string value.
-  ///
-  /// Morally, these are a value import, but until value imports are available
-  /// in the component model, this import function should return the same
-  /// values each time it is called.
-  get-environment: func() -> list<tuple<string, string>>
-
-  /// Get the POSIX-style arguments to the program.
-  get-arguments: func() -> list<string>
-}
diff --git a/crates/test-programs/reactor-tests/wit/deps/wasi-cli-base/exit.wit b/crates/test-programs/reactor-tests/wit/deps/wasi-cli-base/exit.wit
deleted file mode 100644
index 2759e9dd9..000000000
--- a/crates/test-programs/reactor-tests/wit/deps/wasi-cli-base/exit.wit
+++ /dev/null
@@ -1,4 +0,0 @@
-default interface wasi-exit {
-  /// Exit the curerent instance and any linked instances.
-  exit: func(status: result)
-}
diff --git a/crates/test-programs/reactor-tests/wit/test-reactor.wit b/crates/test-programs/reactor-tests/wit/test-reactor.wit
deleted file mode 100644
index 12abad593..000000000
--- a/crates/test-programs/reactor-tests/wit/test-reactor.wit
+++ /dev/null
@@ -1,18 +0,0 @@
-default world test-reactor {
-
-  import environment: wasi-cli-base.environment
-  import streams: io.streams
-  import preopens: wasi-cli-base.preopens
-  import filesystem: filesystem.filesystem
-  import exit: wasi-cli-base.exit
-
-  export add-strings: func(s: list<string>) -> u32
-  export get-strings: func() -> list<string>
-
-  use io.streams.{output-stream}
-
-  export write-strings-to: func(o: output-stream) -> result
-
-  use filesystem.filesystem.{descriptor-stat}
-  export pass-an-imported-record: func(d: descriptor-stat) -> string
-}
diff --git a/crates/test-programs/tests/reactor.rs b/crates/test-programs/tests/reactor.rs
index 16b61c7f3..9cd6ececb 100644
--- a/crates/test-programs/tests/reactor.rs
+++ b/crates/test-programs/tests/reactor.rs
@@ -4,7 +4,9 @@ use wasmtime::{
     component::{Component, Linker},
     Config, Engine, Store,
 };
-use wasmtime_wasi::preview2::{wasi, Table, WasiCtx, WasiCtxBuilder, WasiView};
+use wasmtime_wasi::preview2::wasi::clocks::wall_clock;
+use wasmtime_wasi::preview2::wasi::filesystem::filesystem;
+use wasmtime_wasi::preview2::{self, Table, WasiCtx, WasiCtxBuilder, WasiView};
 
 lazy_static::lazy_static! {
     static ref ENGINE: Engine = {
@@ -22,18 +24,18 @@ lazy_static::lazy_static! {
 include!(concat!(env!("OUT_DIR"), "/reactor_tests_components.rs"));
 
 wasmtime::component::bindgen!({
-    path: "../test-programs/reactor-tests/wit",
+    path: "../wasi/wit",
     world: "test-reactor",
     async: true,
     with: {
-       "environment": wasi::environment,
-       "streams": wasi::streams,
-       "preopens": wasi::preopens,
-       "stdin": wasi::stdin,
-       "stdout": wasi::stdout,
-       "stderr": wasi::stderr,
-       "filesystem": wasi::filesystem,
-       "exit": wasi::exit,
+       "wasi:io/streams": preview2::wasi::io::streams,
+       "wasi:filesystem/filesystem": preview2::wasi::filesystem::filesystem,
+       "wasi:cli-base/environment": preview2::wasi::cli_base::environment,
+       "wasi:cli-base/preopens": preview2::wasi::cli_base::preopens,
+       "wasi:cli-base/exit": preview2::wasi::cli_base::exit,
+       "wasi:cli-base/stdin": preview2::wasi::cli_base::stdin,
+       "wasi:cli-base/stdout": preview2::wasi::cli_base::stdout,
+       "wasi:cli-base/stderr": preview2::wasi::cli_base::stderr,
     },
 });
 
@@ -64,14 +66,14 @@ async fn instantiate(
     let mut linker = Linker::new(&ENGINE);
 
     // All of the imports available to the world are provided by the wasi-common crate:
-    wasi::filesystem::add_to_linker(&mut linker, |x| x)?;
-    wasi::streams::add_to_linker(&mut linker, |x| x)?;
-    wasi::environment::add_to_linker(&mut linker, |x| x)?;
-    wasi::preopens::add_to_linker(&mut linker, |x| x)?;
-    wasi::stdin::add_to_linker(&mut linker, |x| x)?;
-    wasi::stdout::add_to_linker(&mut linker, |x| x)?;
-    wasi::stderr::add_to_linker(&mut linker, |x| x)?;
-    wasi::exit::add_to_linker(&mut linker, |x| x)?;
+    preview2::wasi::filesystem::filesystem::add_to_linker(&mut linker, |x| x)?;
+    preview2::wasi::io::streams::add_to_linker(&mut linker, |x| x)?;
+    preview2::wasi::cli_base::environment::add_to_linker(&mut linker, |x| x)?;
+    preview2::wasi::cli_base::preopens::add_to_linker(&mut linker, |x| x)?;
+    preview2::wasi::cli_base::exit::add_to_linker(&mut linker, |x| x)?;
+    preview2::wasi::cli_base::stdin::add_to_linker(&mut linker, |x| x)?;
+    preview2::wasi::cli_base::stdout::add_to_linker(&mut linker, |x| x)?;
+    preview2::wasi::cli_base::stderr::add_to_linker(&mut linker, |x| x)?;
 
     let mut store = Store::new(&ENGINE, wasi_ctx);
 
@@ -131,12 +133,12 @@ async fn reactor_tests() -> Result<()> {
 
     // Show that the `with` invocation in the macro means we get to re-use the
     // type definitions from inside the `host` crate for these structures:
-    let ds = wasi::filesystem::DescriptorStat {
-        data_access_timestamp: wasi::wall_clock::Datetime {
+    let ds = filesystem::DescriptorStat {
+        data_access_timestamp: wall_clock::Datetime {
             nanoseconds: 123,
             seconds: 45,
         },
-        data_modification_timestamp: wasi::wall_clock::Datetime {
+        data_modification_timestamp: wall_clock::Datetime {
             nanoseconds: 789,
             seconds: 10,
         },
@@ -144,11 +146,11 @@ async fn reactor_tests() -> Result<()> {
         inode: 0,
         link_count: 0,
         size: 0,
-        status_change_timestamp: wasi::wall_clock::Datetime {
+        status_change_timestamp: wall_clock::Datetime {
             nanoseconds: 0,
             seconds: 1,
         },
-        type_: wasi::filesystem::DescriptorType::Unknown,
+        type_: filesystem::DescriptorType::Unknown,
     };
     let expected = format!("{ds:?}");
     let got = reactor.call_pass_an_imported_record(&mut store, ds).await?;
diff --git a/crates/test-programs/tests/wasi-http.rs b/crates/test-programs/tests/wasi-http.rs
index 78c99dc93..0b1a4fd70 100644
--- a/crates/test-programs/tests/wasi-http.rs
+++ b/crates/test-programs/tests/wasi-http.rs
@@ -1,4 +1,4 @@
-#![cfg(feature = "test_programs")]
+#![cfg(all(feature = "test_programs", not(skip_wasi_http_tests)))]
 use wasmtime::{Config, Engine, Linker, Store};
 use wasmtime_wasi::{sync::WasiCtxBuilder, WasiCtx};
 use wasmtime_wasi_http::WasiHttp;
diff --git a/crates/wasi/wit/test.wit b/crates/wasi/wit/test.wit
new file mode 100644
index 000000000..a362fd4d9
--- /dev/null
+++ b/crates/wasi/wit/test.wit
@@ -0,0 +1,19 @@
+// only used as part of `test-programs`
+world test-reactor {
+
+  import wasi:cli-base/environment
+  import wasi:io/streams
+  import wasi:cli-base/preopens
+  import wasi:filesystem/filesystem
+  import wasi:cli-base/exit
+
+  export add-strings: func(s: list<string>) -> u32
+  export get-strings: func() -> list<string>
+
+  use wasi:io/streams.{output-stream}
+
+  export write-strings-to: func(o: output-stream) -> result
+
+  use wasi:filesystem/filesystem.{descriptor-stat}
+  export pass-an-imported-record: func(d: descriptor-stat) -> string
+}
diff --git a/tests/all/component_model/bindgen.rs b/tests/all/component_model/bindgen.rs
index d8c8f3023..c377f08a6 100644
--- a/tests/all/component_model/bindgen.rs
+++ b/tests/all/component_model/bindgen.rs
@@ -14,7 +14,9 @@ mod no_imports {
 
     wasmtime::component::bindgen!({
         inline: "
-            default world no-imports {
+            package foo:foo
+
+            world no-imports {
                 export foo: interface {
                     foo: func()
                 }
@@ -59,7 +61,9 @@ mod one_import {
 
     wasmtime::component::bindgen!({
         inline: "
-            default world one-import {
+            package foo:foo
+
+            world one-import {
                 import foo: interface {
                     foo: func()
                 }
diff --git a/tests/all/component_model/bindgen/results.rs b/tests/all/component_model/bindgen/results.rs
index eaec5cc3a..d0c49e402 100644
--- a/tests/all/component_model/bindgen/results.rs
+++ b/tests/all/component_model/bindgen/results.rs
@@ -9,7 +9,8 @@ mod empty_error {
     use super::*;
     wasmtime::component::bindgen!({
         inline: "
-        default world result-playground {
+        package inline:inline
+        world result-playground {
             import imports: interface {
                 empty-error: func(a: float64) -> result<float64>
             }
@@ -109,7 +110,8 @@ mod string_error {
     use super::*;
     wasmtime::component::bindgen!({
         inline: "
-        default world result-playground {
+        package inline:inline
+        world result-playground {
             import imports: interface {
                 string-error: func(a: float64) -> result<float64, string>
             }
@@ -219,14 +221,18 @@ mod string_error {
 
 mod enum_error {
     use super::*;
+    use exports::foo;
+    use inline::inline::imports;
+
     wasmtime::component::bindgen!({
         inline: "
+        package inline:inline
         interface imports {
             enum e1 { a, b, c }
             enum-error: func(a: float64) -> result<float64, e1>
         }
-        default world result-playground {
-            import imports: self.imports
+        world result-playground {
+            import imports
             export foo: interface {
                 enum e1 { a, b, c }
                 enum-error: func(a: float64) -> result<float64, e1>
@@ -244,7 +250,7 @@ mod enum_error {
                 r#"
             (component
                 (type $err' (enum "a" "b" "c"))
-                (import "imports" (instance $i
+                (import (interface "inline:inline/imports") (instance $i
                     (export $err "err" (type (eq $err')))
                     (export "enum-error" (func (param "a" float64) (result (result float64 (error $err)))))
                 ))
@@ -357,7 +363,7 @@ mod enum_error {
             .expect("no trap")
             .err()
             .expect("error returned");
-        assert_eq!(e, enum_error::foo::E1::A);
+        assert_eq!(e, foo::E1::A);
 
         let e = results
             .foo()
@@ -377,14 +383,18 @@ mod enum_error {
 
 mod record_error {
     use super::*;
+    use exports::foo;
+    use inline::inline::imports;
+
     wasmtime::component::bindgen!({
         inline: "
+        package inline:inline
         interface imports {
             record e2 { line: u32, col: u32 }
             record-error: func(a: float64) -> result<float64, e2>
         }
-        default world result-playground {
-            import imports: self.imports
+        world result-playground {
+            import imports
             export foo: interface {
                 record e2 { line: u32, col: u32 }
                 record-error: func(a: float64) -> result<float64, e2>
@@ -407,7 +417,7 @@ mod record_error {
                     (field "line" u32)
                     (field "col" u32)
                 ))
-                (import "imports" (instance $i
+                (import (interface "inline:inline/imports") (instance $i
                     (export $e2 "e2" (type (eq $e2')))
                     (type $result (result float64 (error $e2)))
                     (export "record-error" (func (param "a" float64) (result $result)))
@@ -525,16 +535,20 @@ mod record_error {
 
 mod variant_error {
     use super::*;
+    use exports::foo;
+    use inline::inline::imports;
+
     wasmtime::component::bindgen!({
         inline: "
+        package inline:inline
         interface imports {
             enum e1 { a, b, c }
             record e2 { line: u32, col: u32 }
             variant e3 { E1(e1), E2(e2) }
             variant-error: func(a: float64) -> result<float64, e3>
         }
-        default world result-playground {
-            import imports: self.imports
+        world result-playground {
+            import imports
             export foo: interface {
                 enum e1 { a, b, c }
                 record e2 { line: u32, col: u32 }
@@ -559,7 +573,7 @@ mod variant_error {
                     (case "E1" $e1')
                     (case "E2" $e2')
                 ))
-                (import "imports" (instance $i
+                (import (interface "inline:inline/imports") (instance $i
                     (export $e1 "e1" (type (eq $e1')))
                     (export $e2 "e2" (type (eq $e2')))
                     (type $e3' (variant
@@ -710,7 +724,8 @@ mod with_remapping {
 
     wasmtime::component::bindgen!({
         inline: "
-        default world result-playground {
+        package inline:inline
+        world result-playground {
             import imports: interface {
                 empty-error: func(a: float64) -> result<float64>
             }