Add Fuchsia SDK.

Bug: 120856007
Test: Build walleye.
Change-Id: I6b5ebe9bff4e729783bca67d35c291878fbe16cb
diff --git a/pkg/async-default/include/lib/async/default.h b/pkg/async-default/include/lib/async/default.h
new file mode 100644
index 0000000..b171058
--- /dev/null
+++ b/pkg/async-default/include/lib/async/default.h
@@ -0,0 +1,23 @@
+// Copyright 2017 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef LIB_ASYNC_DEFAULT_H_
+#define LIB_ASYNC_DEFAULT_H_
+
+#include <lib/async/dispatcher.h>
+#include <zircon/compiler.h>
+
+__BEGIN_CDECLS
+
+// Gets the current thread's default asynchronous dispatcher interface.
+// Returns |NULL| if none.
+__EXPORT async_dispatcher_t* async_get_default_dispatcher(void);
+
+// Sets the current thread's default asynchronous dispatcher interface.
+// May be set to |NULL| if this thread doesn't have a default dispatcher.
+__EXPORT void async_set_default_dispatcher(async_dispatcher_t* dispatcher);
+
+__END_CDECLS
+
+#endif  // LIB_ASYNC_DEFAULT_H_
diff --git a/pkg/async-default/meta.json b/pkg/async-default/meta.json
new file mode 100644
index 0000000..2394825
--- /dev/null
+++ b/pkg/async-default/meta.json
@@ -0,0 +1,23 @@
+{
+  "binaries": {
+    "arm64": {
+      "debug": ".build-id/48/624ebaefd10ab212943f16760a00f469ec307e.debug", 
+      "dist": "arch/arm64/dist/libasync-default.so", 
+      "link": "arch/arm64/lib/libasync-default.so"
+    }, 
+    "x64": {
+      "debug": ".build-id/5e/3c55aea09e8943ae76d3603cc8c0b1ba27bfb7.debug", 
+      "dist": "arch/x64/dist/libasync-default.so", 
+      "link": "arch/x64/lib/libasync-default.so"
+    }
+  }, 
+  "deps": [], 
+  "format": "shared", 
+  "headers": [
+    "pkg/async-default/include/lib/async/default.h"
+  ], 
+  "include_dir": "pkg/async-default/include", 
+  "name": "async-default", 
+  "root": "pkg/async-default", 
+  "type": "cc_prebuilt_library"
+}
\ No newline at end of file
diff --git a/pkg/async-loop-cpp/include/lib/async-loop/cpp/loop.h b/pkg/async-loop-cpp/include/lib/async-loop/cpp/loop.h
new file mode 100644
index 0000000..6168aba
--- /dev/null
+++ b/pkg/async-loop-cpp/include/lib/async-loop/cpp/loop.h
@@ -0,0 +1,121 @@
+// Copyright 2017 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#pragma once
+
+#include <lib/async-loop/loop.h>
+#include <lib/async/default.h>
+#include <lib/zx/time.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include <threads.h>
+#include <zircon/compiler.h>
+
+namespace async {
+
+// C++ wrapper for an asynchronous dispatch loop.
+//
+// This class is thread-safe.
+class Loop {
+public:
+    // Creates a message loop.
+    // All operations on the message loop are thread-safe (except destroy).
+    //
+    // Note that it's ok to run the loop on a different thread from the one
+    // upon which it was created.
+    //
+    // |config| provides configuration for the message loop.  Must not be null.
+    //
+    // See also |kAsyncLoopConfigAttachToThread| and |kAsyncLoopConfigNoAttachToThread|.
+    explicit Loop(const async_loop_config_t* config);
+
+    Loop(const Loop&) = delete;
+    Loop(Loop&&) = delete;
+    Loop& operator=(const Loop&) = delete;
+    Loop& operator=(Loop&&) = delete;
+
+    // Destroys the message loop.
+    // Implicitly calls |Shutdown()|.
+    ~Loop();
+
+    // Gets the underlying message loop structure.
+    async_loop_t* loop() const { return loop_; }
+
+    // Gets the loop's asynchronous dispatch interface.
+    async_dispatcher_t* dispatcher() const { return async_loop_get_dispatcher(loop_); }
+
+    // Shuts down the message loop, notifies handlers which asked to handle shutdown.
+    // The message loop must not currently be running on any threads other than
+    // those started by |StartThread()| which this function will join.
+    //
+    // Does nothing if already shutting down.
+    void Shutdown();
+
+    // Runs the message loop on the current thread.
+    // This function can be called on multiple threads to setup a multi-threaded
+    // dispatcher.
+    //
+    // Dispatches events until the |deadline| expires or the loop is quitted.
+    // Use |ZX_TIME_INFINITE| to dispatch events indefinitely.
+    //
+    // If |once| is true, performs a single unit of work then returns.
+    //
+    // Returns |ZX_OK| if the dispatcher returns after one cycle.
+    // Returns |ZX_ERR_TIMED_OUT| if the deadline expired.
+    // Returns |ZX_ERR_CANCELED| if the loop quitted.
+    // Returns |ZX_ERR_BAD_STATE| if the loop was shut down with |Shutdown()|.
+    zx_status_t Run(zx::time deadline = zx::time::infinite(), bool once = false);
+
+    // Dispatches events until there are none remaining, and then returns
+    // without waiting. This is useful for unit testing, because the behavior
+    // doesn't depend on time.
+    //
+    // Returns |ZX_OK| if the dispatcher reaches an idle state.
+    // Returns |ZX_ERR_CANCELED| if the loop quitted.
+    // Returns |ZX_ERR_BAD_STATE| if the loop was shut down with |Shutdown()|.
+    zx_status_t RunUntilIdle();
+
+    // Quits the message loop.
+    // Active invocations of |Run()| and threads started using |StartThread()|
+    // will eventually terminate upon completion of their current unit of work.
+    //
+    // Subsequent calls to |Run()| or |StartThread()| will return immediately
+    // until |ResetQuit()| is called.
+    void Quit();
+
+    // Resets the quit state of the message loop so that it can be restarted
+    // using |Run()| or |StartThread()|.
+    //
+    // This function must only be called when the message loop is not running.
+    // The caller must ensure all active invocations of |Run()| and threads
+    // started using |StartThread()| have terminated before resetting the quit state.
+    //
+    // Returns |ZX_OK| if the loop's state was |ASYNC_LOOP_RUNNABLE| or |ASYNC_LOOP_QUIT|.
+    // Returns |ZX_ERR_BAD_STATE| if the loop's state was |ASYNC_LOOP_SHUTDOWN| or if
+    // the message loop is currently active on one or more threads.
+    zx_status_t ResetQuit();
+
+    // Returns the current state of the message loop.
+    async_loop_state_t GetState() const;
+
+    // Starts a message loop running on a new thread.
+    // The thread will run until the loop quits.
+    //
+    // |name| is the desired name for the new thread, may be NULL.
+    // If |out_thread| is not NULL, it is set to the new thread identifier.
+    //
+    // Returns |ZX_OK| on success.
+    // Returns |ZX_ERR_BAD_STATE| if the loop was shut down with |async_loop_shutdown()|.
+    // Returns |ZX_ERR_NO_MEMORY| if allocation or thread creation failed.
+    zx_status_t StartThread(const char* name = nullptr, thrd_t* out_thread = nullptr);
+
+    // Blocks until all dispatch threads started with |StartThread()|
+    // have terminated.
+    void JoinThreads();
+
+private:
+    async_loop_t* loop_;
+};
+
+} // namespace async
diff --git a/pkg/async-loop-cpp/loop_wrapper.cpp b/pkg/async-loop-cpp/loop_wrapper.cpp
new file mode 100644
index 0000000..cc866ec
--- /dev/null
+++ b/pkg/async-loop-cpp/loop_wrapper.cpp
@@ -0,0 +1,52 @@
+// Copyright 2017 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <lib/async-loop/cpp/loop.h>
+
+#include <zircon/assert.h>
+
+namespace async {
+
+Loop::Loop(const async_loop_config_t* config) {
+    zx_status_t status = async_loop_create(config, &loop_);
+    ZX_ASSERT_MSG(status == ZX_OK, "status=%d", status);
+}
+
+Loop::~Loop() {
+    async_loop_destroy(loop_);
+}
+
+void Loop::Shutdown() {
+    async_loop_shutdown(loop_);
+}
+
+zx_status_t Loop::Run(zx::time deadline, bool once) {
+    return async_loop_run(loop_, deadline.get(), once);
+}
+
+zx_status_t Loop::RunUntilIdle() {
+    return async_loop_run_until_idle(loop_);
+}
+
+void Loop::Quit() {
+    async_loop_quit(loop_);
+}
+
+zx_status_t Loop::ResetQuit() {
+    return async_loop_reset_quit(loop_);
+}
+
+async_loop_state_t Loop::GetState() const {
+    return async_loop_get_state(loop_);
+}
+
+zx_status_t Loop::StartThread(const char* name, thrd_t* out_thread) {
+    return async_loop_start_thread(loop_, name, out_thread);
+}
+
+void Loop::JoinThreads() {
+    async_loop_join_threads(loop_);
+}
+
+} // namespace async
diff --git a/pkg/async-loop-cpp/meta.json b/pkg/async-loop-cpp/meta.json
new file mode 100644
index 0000000..950712f
--- /dev/null
+++ b/pkg/async-loop-cpp/meta.json
@@ -0,0 +1,24 @@
+{
+  "banjo_deps": [], 
+  "deps": [
+    "async", 
+    "async-default", 
+    "async-loop", 
+    "zx"
+  ], 
+  "fidl_deps": [], 
+  "files": [
+    "pkg/async-loop-cpp/loop_wrapper.cpp", 
+    "pkg/async-loop-cpp/include/lib/async-loop/cpp/loop.h"
+  ], 
+  "headers": [
+    "pkg/async-loop-cpp/include/lib/async-loop/cpp/loop.h"
+  ], 
+  "include_dir": "pkg/async-loop-cpp/include", 
+  "name": "async-loop-cpp", 
+  "root": "pkg/async-loop-cpp", 
+  "sources": [
+    "pkg/async-loop-cpp/loop_wrapper.cpp"
+  ], 
+  "type": "cc_source_library"
+}
\ No newline at end of file
diff --git a/pkg/async-loop/include/lib/async-loop/loop.h b/pkg/async-loop/include/lib/async-loop/loop.h
new file mode 100644
index 0000000..1335cdb
--- /dev/null
+++ b/pkg/async-loop/include/lib/async-loop/loop.h
@@ -0,0 +1,177 @@
+// Copyright 2017 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+//
+// Provides an implementation of a simple thread-safe asynchronous
+// dispatcher based on a Zircon completion port.  The implementation
+// is designed to avoid most dynamic memory allocation except for that
+// which is required to create the loop in the first place or to manage
+// the list of running threads.
+//
+// See README.md for example usage.
+//
+
+#ifndef LIB_ASYNC_LOOP_LOOP_H_
+#define LIB_ASYNC_LOOP_LOOP_H_
+
+#include <stdbool.h>
+#include <stddef.h>
+#include <threads.h>
+
+#include <zircon/compiler.h>
+
+#include <lib/async/dispatcher.h>
+
+__BEGIN_CDECLS
+
+// Pointer to a message loop created using |async_loop_create()|.
+typedef struct async_loop async_loop_t;
+
+// Message loop configuration structure.
+typedef void(async_loop_callback_t)(async_loop_t* loop, void* data);
+typedef struct async_loop_config {
+    // If true, the loop will automatically register itself as the default
+    // dispatcher for the thread upon which it was created and will
+    // automatically unregister itself when destroyed (which must occur on
+    // the same thread).
+    //
+    // If false, the loop will not do this.  The loop's creator is then
+    // resposible for retrieving the loop's dispatcher using |async_loop_get_dispatcher()|
+    // and passing it around explicitly or calling |async_set_default_dispatcher()| as needed.
+    //
+    // Note that the loop can be used even without setting it as the current
+    // thread's default.
+    bool make_default_for_current_thread;
+
+    // A function to call before the dispatcher invokes each handler, or NULL if none.
+    async_loop_callback_t* prologue;
+
+    // A function to call after the dispatcher invokes each handler, or NULL if none.
+    async_loop_callback_t* epilogue;
+
+    // Data to pass to the callback functions.
+    void* data;
+} async_loop_config_t;
+
+// Simple config that when passed to async_loop_create will create a loop
+// that will automatically register itself as the default
+// dispatcher for the thread upon which it was created and will
+// automatically unregister itself when destroyed (which must occur on
+// the same thread).
+extern const async_loop_config_t kAsyncLoopConfigAttachToThread;
+
+// Simple config that when passed to async_loop_create will create a loop
+// that is not registered to the current thread.
+extern const async_loop_config_t kAsyncLoopConfigNoAttachToThread;
+
+// Creates a message loop and returns a pointer to it in |out_loop|.
+// All operations on the message loop are thread-safe (except destroy).
+//
+// Note that it's ok to run the loop on a different thread from the one
+// upon which it was created.
+//
+// |config| provides configuration for the message loop. Must not be null.
+//
+// Returns |ZX_OK| on success.
+// Returns |ZX_ERR_NO_MEMORY| if allocation failed.
+// May return other errors if the necessary internal handles could not be created.
+//
+// See also |kAsyncLoopConfigAttachToThread| and |kAsyncLoopConfigNoAttachToThread|.
+zx_status_t async_loop_create(const async_loop_config_t* config,
+                              async_loop_t** out_loop);
+
+// Gets the the message loop's asynchronous dispatch interface.
+async_dispatcher_t* async_loop_get_dispatcher(async_loop_t* loop);
+
+// Gets the message loop associated with the specified asynchronous dispatch interface
+//
+// This function assumes the dispatcher is backed by an |async_loop_t| which was created
+// using |async_loop_create()|.  Its behavior is undefined if used with other dispatcher
+// implementations.
+async_loop_t* async_loop_from_dispatcher(async_dispatcher_t* dispatcher);
+
+// Shuts down the message loop, notifies handlers which asked to handle shutdown.
+// The message loop must not currently be running on any threads other than
+// those started by |async_loop_start_thread()| which this function will join.
+//
+// Does nothing if already shutting down.
+void async_loop_shutdown(async_loop_t* loop);
+
+// Destroys the message loop.
+// Implicitly calls |async_loop_shutdown()| and joins all threads started
+// using |async_loop_start_thread()| before destroying the loop itself.
+void async_loop_destroy(async_loop_t* loop);
+
+// Runs the message loop on the current thread.
+// This function can be called on multiple threads to setup a multi-threaded
+// dispatcher.
+//
+// Dispatches events until the |deadline| expires or the loop is quitted.
+// Use |ZX_TIME_INFINITE| to dispatch events indefinitely.
+//
+// If |once| is true, performs a single unit of work then returns.
+//
+// Returns |ZX_OK| if the dispatcher returns after one cycle.
+// Returns |ZX_ERR_TIMED_OUT| if the deadline expired.
+// Returns |ZX_ERR_CANCELED| if the loop quitted.
+// Returns |ZX_ERR_BAD_STATE| if the loop was shut down with |async_loop_shutdown()|.
+zx_status_t async_loop_run(async_loop_t* loop, zx_time_t deadline, bool once);
+
+// Dispatches events until there are none remaining, and then returns without
+// waiting. This is useful for unit testing, because the behavior doesn't depend
+// on time.
+//
+// Returns |ZX_OK| if the dispatcher reaches an idle state.
+// Returns |ZX_ERR_CANCELED| if the loop quitted.
+// Returns |ZX_ERR_BAD_STATE| if the loop was shut down with |async_loop_shutdown()|.
+zx_status_t async_loop_run_until_idle(async_loop_t* loop);
+
+// Quits the message loop.
+// Active invocations of |async_loop_run()| and threads started using
+// |async_loop_start_thread()| will eventually terminate upon completion of their
+// current unit of work.
+//
+// Subsequent calls to |async_loop_run()| or |async_loop_start_thread()|
+// will return immediately until |async_loop_reset_quit()| is called.
+void async_loop_quit(async_loop_t* loop);
+
+// Resets the quit state of the message loop so that it can be restarted
+// using |async_loop_run()| or |async_loop_start_thread()|.
+//
+// This function must only be called when the message loop is not running.
+// The caller must ensure all active invocations of |async_loop_run()| and
+// threads started using |async_loop_start_thread()| have terminated before
+// resetting the quit state.
+//
+// Returns |ZX_OK| if the loop's state was |ASYNC_LOOP_RUNNABLE| or |ASYNC_LOOP_QUIT|.
+// Returns |ZX_ERR_BAD_STATE| if the loop's state was |ASYNC_LOOP_SHUTDOWN| or if
+// the message loop is currently active on one or more threads.
+zx_status_t async_loop_reset_quit(async_loop_t* loop);
+
+// Returns the current state of the message loop.
+typedef uint32_t async_loop_state_t;
+#define ASYNC_LOOP_RUNNABLE ((async_loop_state_t) 0)
+#define ASYNC_LOOP_QUIT ((async_loop_state_t) 1)
+#define ASYNC_LOOP_SHUTDOWN ((async_loop_state_t) 2)
+async_loop_state_t async_loop_get_state(async_loop_t* loop);
+
+// Starts a message loop running on a new thread.
+// The thread will run until the loop quits.
+//
+// |name| is the desired name for the new thread, may be NULL.
+// If |out_thread| is not NULL, it is set to the new thread identifier.
+//
+// Returns |ZX_OK| on success.
+// Returns |ZX_ERR_BAD_STATE| if the loop was shut down with |async_loop_shutdown()|.
+// Returns |ZX_ERR_NO_MEMORY| if allocation or thread creation failed.
+zx_status_t async_loop_start_thread(async_loop_t* loop, const char* name,
+                                    thrd_t* out_thread);
+
+// Blocks until all dispatch threads started with |async_loop_start_thread()|
+// have terminated.
+void async_loop_join_threads(async_loop_t* loop);
+
+__END_CDECLS
+
+#endif  // LIB_ASYNC_LOOP_LOOP_H_
\ No newline at end of file
diff --git a/pkg/async-loop/loop.c b/pkg/async-loop/loop.c
new file mode 100644
index 0000000..e70627a
--- /dev/null
+++ b/pkg/async-loop/loop.c
@@ -0,0 +1,797 @@
+// Copyright 2017 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef _ALL_SOURCE
+#define _ALL_SOURCE // Enables thrd_create_with_name in <threads.h>.
+#endif
+#include <lib/async-loop/loop.h>
+
+#include <assert.h>
+#include <stdatomic.h>
+#include <stdlib.h>
+
+#include <zircon/assert.h>
+#include <zircon/listnode.h>
+#include <zircon/syscalls.h>
+#include <zircon/syscalls/hypervisor.h>
+
+#include <lib/async/default.h>
+#include <lib/async/exception.h>
+#include <lib/async/receiver.h>
+#include <lib/async/task.h>
+#include <lib/async/trap.h>
+#include <lib/async/wait.h>
+
+// The port wait key associated with the dispatcher's control messages.
+#define KEY_CONTROL (0u)
+
+static zx_time_t async_loop_now(async_dispatcher_t* dispatcher);
+static zx_status_t async_loop_begin_wait(async_dispatcher_t* dispatcher, async_wait_t* wait);
+static zx_status_t async_loop_cancel_wait(async_dispatcher_t* dispatcher, async_wait_t* wait);
+static zx_status_t async_loop_post_task(async_dispatcher_t* dispatcher, async_task_t* task);
+static zx_status_t async_loop_cancel_task(async_dispatcher_t* dispatcher, async_task_t* task);
+static zx_status_t async_loop_queue_packet(async_dispatcher_t* dispatcher, async_receiver_t* receiver,
+                                           const zx_packet_user_t* data);
+static zx_status_t async_loop_set_guest_bell_trap(
+    async_dispatcher_t* dispatcher, async_guest_bell_trap_t* trap,
+    zx_handle_t guest, zx_vaddr_t addr, size_t length);
+static zx_status_t async_loop_bind_exception_port(async_dispatcher_t* async,
+                                                  async_exception_t* exception);
+static zx_status_t async_loop_unbind_exception_port(async_dispatcher_t* async,
+                                                    async_exception_t* exception);
+static zx_status_t async_loop_resume_from_exception(async_dispatcher_t* async,
+                                                    async_exception_t* exception,
+                                                    zx_handle_t task,
+                                                    uint32_t options);
+
+static const async_ops_t async_loop_ops = {
+    .version = ASYNC_OPS_V2,
+    .reserved = 0,
+    .v1 = {
+        .now = async_loop_now,
+        .begin_wait = async_loop_begin_wait,
+        .cancel_wait = async_loop_cancel_wait,
+        .post_task = async_loop_post_task,
+        .cancel_task = async_loop_cancel_task,
+        .queue_packet = async_loop_queue_packet,
+        .set_guest_bell_trap = async_loop_set_guest_bell_trap,
+    },
+    .v2 = {
+        .bind_exception_port = async_loop_bind_exception_port,
+        .unbind_exception_port = async_loop_unbind_exception_port,
+        .resume_from_exception = async_loop_resume_from_exception,
+    },
+};
+
+typedef struct thread_record {
+    list_node_t node;
+    thrd_t thread;
+} thread_record_t;
+
+const async_loop_config_t kAsyncLoopConfigAttachToThread = {
+    .make_default_for_current_thread = true};
+const async_loop_config_t kAsyncLoopConfigNoAttachToThread = {
+    .make_default_for_current_thread = false};
+
+typedef struct async_loop {
+    async_dispatcher_t dispatcher; // must be first (the loop inherits from async_dispatcher_t)
+    async_loop_config_t config; // immutable
+    zx_handle_t port; // immutable
+    zx_handle_t timer; // immutable
+
+    _Atomic async_loop_state_t state;
+    atomic_uint active_threads; // number of active dispatch threads
+
+    mtx_t lock; // guards the lists and the dispatching tasks flag
+    bool dispatching_tasks; // true while the loop is busy dispatching tasks
+    list_node_t wait_list; // most recently added first
+    list_node_t task_list; // pending tasks, earliest deadline first
+    list_node_t due_list; // due tasks, earliest deadline first
+    list_node_t thread_list; // earliest created thread first
+    list_node_t exception_list; // most recently added first
+} async_loop_t;
+
+static zx_status_t async_loop_run_once(async_loop_t* loop, zx_time_t deadline);
+static zx_status_t async_loop_dispatch_wait(async_loop_t* loop, async_wait_t* wait,
+                                            zx_status_t status, const zx_packet_signal_t* signal);
+static zx_status_t async_loop_dispatch_tasks(async_loop_t* loop);
+static void async_loop_dispatch_task(async_loop_t* loop, async_task_t* task,
+                                     zx_status_t status);
+static zx_status_t async_loop_dispatch_packet(async_loop_t* loop, async_receiver_t* receiver,
+                                              zx_status_t status, const zx_packet_user_t* data);
+static zx_status_t async_loop_dispatch_guest_bell_trap(async_loop_t* loop,
+                                                       async_guest_bell_trap_t* trap,
+                                                       zx_status_t status,
+                                                       const zx_packet_guest_bell_t* bell);
+static zx_status_t async_loop_dispatch_exception(async_loop_t* loop,
+                                                 async_exception_t* exception,
+                                                 zx_status_t status,
+                                                 const zx_port_packet_t* report);
+static void async_loop_wake_threads(async_loop_t* loop);
+static void async_loop_insert_task_locked(async_loop_t* loop, async_task_t* task);
+static void async_loop_restart_timer_locked(async_loop_t* loop);
+static void async_loop_invoke_prologue(async_loop_t* loop);
+static void async_loop_invoke_epilogue(async_loop_t* loop);
+
+static_assert(sizeof(list_node_t) <= sizeof(async_state_t),
+              "async_state_t too small");
+
+#define TO_NODE(type, ptr) ((list_node_t*)&ptr->state)
+#define FROM_NODE(type, ptr) ((type*)((char*)(ptr)-offsetof(type, state)))
+
+static inline list_node_t* wait_to_node(async_wait_t* wait) {
+    return TO_NODE(async_wait_t, wait);
+}
+
+static inline async_wait_t* node_to_wait(list_node_t* node) {
+    return FROM_NODE(async_wait_t, node);
+}
+
+static inline list_node_t* task_to_node(async_task_t* task) {
+    return TO_NODE(async_task_t, task);
+}
+
+static inline async_task_t* node_to_task(list_node_t* node) {
+    return FROM_NODE(async_task_t, node);
+}
+
+static inline list_node_t* exception_to_node(async_exception_t* exception) {
+    return TO_NODE(async_exception_t, exception);
+}
+
+static inline async_exception_t* node_to_exception(list_node_t* node) {
+    return FROM_NODE(async_exception_t, node);
+}
+
+zx_status_t async_loop_create(const async_loop_config_t* config, async_loop_t** out_loop) {
+    ZX_DEBUG_ASSERT(out_loop);
+    ZX_DEBUG_ASSERT(config != NULL);
+
+    async_loop_t* loop = calloc(1u, sizeof(async_loop_t));
+    if (!loop)
+        return ZX_ERR_NO_MEMORY;
+    atomic_init(&loop->state, ASYNC_LOOP_RUNNABLE);
+    atomic_init(&loop->active_threads, 0u);
+
+    loop->dispatcher.ops = &async_loop_ops;
+    loop->config = *config;
+    mtx_init(&loop->lock, mtx_plain);
+    list_initialize(&loop->wait_list);
+    list_initialize(&loop->task_list);
+    list_initialize(&loop->due_list);
+    list_initialize(&loop->thread_list);
+    list_initialize(&loop->exception_list);
+
+    zx_status_t status = zx_port_create(0u, &loop->port);
+    if (status == ZX_OK)
+        status = zx_timer_create(0u, ZX_CLOCK_MONOTONIC, &loop->timer);
+    if (status == ZX_OK) {
+        status = zx_object_wait_async(loop->timer, loop->port, KEY_CONTROL,
+                                      ZX_TIMER_SIGNALED,
+                                      ZX_WAIT_ASYNC_REPEATING);
+    }
+    if (status == ZX_OK) {
+        *out_loop = loop;
+        if (loop->config.make_default_for_current_thread) {
+            ZX_DEBUG_ASSERT(async_get_default_dispatcher() == NULL);
+            async_set_default_dispatcher(&loop->dispatcher);
+        }
+    } else {
+        loop->config.make_default_for_current_thread = false;
+        async_loop_destroy(loop);
+    }
+    return status;
+}
+
+void async_loop_destroy(async_loop_t* loop) {
+    ZX_DEBUG_ASSERT(loop);
+
+    async_loop_shutdown(loop);
+
+    zx_handle_close(loop->port);
+    zx_handle_close(loop->timer);
+    mtx_destroy(&loop->lock);
+    free(loop);
+}
+
+void async_loop_shutdown(async_loop_t* loop) {
+    ZX_DEBUG_ASSERT(loop);
+
+    async_loop_state_t prior_state =
+        atomic_exchange_explicit(&loop->state, ASYNC_LOOP_SHUTDOWN,
+                                 memory_order_acq_rel);
+    if (prior_state == ASYNC_LOOP_SHUTDOWN)
+        return;
+
+    async_loop_wake_threads(loop);
+    async_loop_join_threads(loop);
+
+    list_node_t* node;
+    while ((node = list_remove_head(&loop->wait_list))) {
+        async_wait_t* wait = node_to_wait(node);
+        async_loop_dispatch_wait(loop, wait, ZX_ERR_CANCELED, NULL);
+    }
+    while ((node = list_remove_head(&loop->due_list))) {
+        async_task_t* task = node_to_task(node);
+        async_loop_dispatch_task(loop, task, ZX_ERR_CANCELED);
+    }
+    while ((node = list_remove_head(&loop->task_list))) {
+        async_task_t* task = node_to_task(node);
+        async_loop_dispatch_task(loop, task, ZX_ERR_CANCELED);
+    }
+    while ((node = list_remove_head(&loop->exception_list))) {
+        async_exception_t* exception = node_to_exception(node);
+        async_loop_dispatch_exception(loop, exception, ZX_ERR_CANCELED, NULL);
+    }
+
+    if (loop->config.make_default_for_current_thread) {
+        ZX_DEBUG_ASSERT(async_get_default_dispatcher() == &loop->dispatcher);
+        async_set_default_dispatcher(NULL);
+    }
+}
+
+zx_status_t async_loop_run(async_loop_t* loop, zx_time_t deadline, bool once) {
+    ZX_DEBUG_ASSERT(loop);
+
+    zx_status_t status;
+    atomic_fetch_add_explicit(&loop->active_threads, 1u, memory_order_acq_rel);
+    do {
+        status = async_loop_run_once(loop, deadline);
+    } while (status == ZX_OK && !once);
+    atomic_fetch_sub_explicit(&loop->active_threads, 1u, memory_order_acq_rel);
+    return status;
+}
+
+zx_status_t async_loop_run_until_idle(async_loop_t* loop) {
+    zx_status_t status = async_loop_run(loop, 0, false);
+    if (status == ZX_ERR_TIMED_OUT) {
+        status = ZX_OK;
+    }
+    return status;
+}
+
+static zx_status_t async_loop_run_once(async_loop_t* loop, zx_time_t deadline) {
+    async_loop_state_t state = atomic_load_explicit(&loop->state, memory_order_acquire);
+    if (state == ASYNC_LOOP_SHUTDOWN)
+        return ZX_ERR_BAD_STATE;
+    if (state != ASYNC_LOOP_RUNNABLE)
+        return ZX_ERR_CANCELED;
+
+    zx_port_packet_t packet;
+    zx_status_t status = zx_port_wait(loop->port, deadline, &packet);
+    if (status != ZX_OK)
+        return status;
+
+    if (packet.key == KEY_CONTROL) {
+        // Handle wake-up packets.
+        if (packet.type == ZX_PKT_TYPE_USER)
+            return ZX_OK;
+
+        // Handle task timer expirations.
+        if (packet.type == ZX_PKT_TYPE_SIGNAL_REP &&
+            packet.signal.observed & ZX_TIMER_SIGNALED) {
+            return async_loop_dispatch_tasks(loop);
+        }
+    } else {
+        // Handle wait completion packets.
+        if (packet.type == ZX_PKT_TYPE_SIGNAL_ONE) {
+            async_wait_t* wait = (void*)(uintptr_t)packet.key;
+            mtx_lock(&loop->lock);
+            list_delete(wait_to_node(wait));
+            mtx_unlock(&loop->lock);
+            return async_loop_dispatch_wait(loop, wait, packet.status, &packet.signal);
+        }
+
+        // Handle queued user packets.
+        if (packet.type == ZX_PKT_TYPE_USER) {
+            async_receiver_t* receiver = (void*)(uintptr_t)packet.key;
+            return async_loop_dispatch_packet(loop, receiver, packet.status, &packet.user);
+        }
+
+        // Handle guest bell trap packets.
+        if (packet.type == ZX_PKT_TYPE_GUEST_BELL) {
+            async_guest_bell_trap_t* trap = (void*)(uintptr_t)packet.key;
+            return async_loop_dispatch_guest_bell_trap(
+                loop, trap, packet.status, &packet.guest_bell);
+        }
+
+        // Handle exception packets.
+        if (ZX_PKT_IS_EXCEPTION(packet.type)) {
+            async_exception_t* exception = (void*)(uintptr_t)packet.key;
+            return async_loop_dispatch_exception(loop, exception, packet.status,
+                                                 &packet);
+        }
+    }
+
+    ZX_DEBUG_ASSERT(false);
+    return ZX_ERR_INTERNAL;
+}
+
+async_dispatcher_t* async_loop_get_dispatcher(async_loop_t* loop) {
+    // Note: The loop's implementation inherits from async_t so we can upcast to it.
+    return (async_dispatcher_t*)loop;
+}
+
+async_loop_t* async_loop_from_dispatcher(async_dispatcher_t* async) {
+    return (async_loop_t*)async;
+}
+
+static zx_status_t async_loop_dispatch_guest_bell_trap(async_loop_t* loop,
+                                                       async_guest_bell_trap_t* trap,
+                                                       zx_status_t status,
+                                                       const zx_packet_guest_bell_t* bell) {
+    async_loop_invoke_prologue(loop);
+    trap->handler((async_dispatcher_t*)loop, trap, status, bell);
+    async_loop_invoke_epilogue(loop);
+    return ZX_OK;
+}
+
+static zx_status_t async_loop_dispatch_wait(async_loop_t* loop, async_wait_t* wait,
+                                            zx_status_t status, const zx_packet_signal_t* signal) {
+    async_loop_invoke_prologue(loop);
+    wait->handler((async_dispatcher_t*)loop, wait, status, signal);
+    async_loop_invoke_epilogue(loop);
+    return ZX_OK;
+}
+
+static zx_status_t async_loop_dispatch_tasks(async_loop_t* loop) {
+    // Dequeue and dispatch one task at a time in case an earlier task wants
+    // to cancel a later task which has also come due.  At most one thread
+    // can dispatch tasks at any given moment (to preserve serial ordering).
+    // Timer restarts are suppressed until we run out of tasks to dispatch.
+    mtx_lock(&loop->lock);
+    if (!loop->dispatching_tasks) {
+        loop->dispatching_tasks = true;
+
+        // Extract all of the tasks that are due into |due_list| for dispatch
+        // unless we already have some waiting from a previous iteration which
+        // we would like to process in order.
+        list_node_t* node;
+        if (list_is_empty(&loop->due_list)) {
+            zx_time_t due_time = async_loop_now((async_dispatcher_t*)loop);
+            list_node_t* tail = NULL;
+            list_for_every(&loop->task_list, node) {
+                if (node_to_task(node)->deadline > due_time)
+                    break;
+                tail = node;
+            }
+            if (tail) {
+                list_node_t* head = loop->task_list.next;
+                loop->task_list.next = tail->next;
+                tail->next->prev = &loop->task_list;
+                loop->due_list.next = head;
+                head->prev = &loop->due_list;
+                loop->due_list.prev = tail;
+                tail->next = &loop->due_list;
+            }
+        }
+
+        // Dispatch all due tasks.  Note that they might be canceled concurrently
+        // so we need to grab the lock during each iteration to fetch the next
+        // item from the list.
+        while ((node = list_remove_head(&loop->due_list))) {
+            mtx_unlock(&loop->lock);
+
+            // Invoke the handler.  Note that it might destroy itself.
+            async_task_t* task = node_to_task(node);
+            async_loop_dispatch_task(loop, task, ZX_OK);
+
+            mtx_lock(&loop->lock);
+            async_loop_state_t state = atomic_load_explicit(&loop->state, memory_order_acquire);
+            if (state != ASYNC_LOOP_RUNNABLE)
+                break;
+        }
+
+        loop->dispatching_tasks = false;
+        async_loop_restart_timer_locked(loop);
+    }
+    mtx_unlock(&loop->lock);
+    return ZX_OK;
+}
+
+static void async_loop_dispatch_task(async_loop_t* loop,
+                                     async_task_t* task,
+                                     zx_status_t status) {
+    // Invoke the handler.  Note that it might destroy itself.
+    async_loop_invoke_prologue(loop);
+    task->handler((async_dispatcher_t*)loop, task, status);
+    async_loop_invoke_epilogue(loop);
+}
+
+static zx_status_t async_loop_dispatch_packet(async_loop_t* loop, async_receiver_t* receiver,
+                                              zx_status_t status, const zx_packet_user_t* data) {
+    // Invoke the handler.  Note that it might destroy itself.
+    async_loop_invoke_prologue(loop);
+    receiver->handler((async_dispatcher_t*)loop, receiver, status, data);
+    async_loop_invoke_epilogue(loop);
+    return ZX_OK;
+}
+
+static zx_status_t async_loop_dispatch_exception(async_loop_t* loop,
+                                                 async_exception_t* exception,
+                                                 zx_status_t status,
+                                                 const zx_port_packet_t* report) {
+    // Invoke the handler.  Note that it might destroy itself.
+    async_loop_invoke_prologue(loop);
+    exception->handler((async_dispatcher_t*)loop, exception, status, report);
+    async_loop_invoke_epilogue(loop);
+    return ZX_OK;
+}
+
+void async_loop_quit(async_loop_t* loop) {
+    ZX_DEBUG_ASSERT(loop);
+
+    async_loop_state_t expected_state = ASYNC_LOOP_RUNNABLE;
+    if (!atomic_compare_exchange_strong_explicit(&loop->state, &expected_state,
+                                                 ASYNC_LOOP_QUIT,
+                                                 memory_order_acq_rel, memory_order_acquire))
+        return;
+
+    async_loop_wake_threads(loop);
+}
+
+static void async_loop_wake_threads(async_loop_t* loop) {
+    // Queue enough packets to awaken all active threads.
+    // This is safe because any new threads which join the pool first increment the
+    // active thread count then check the loop state, so the count we observe here
+    // cannot be less than the number of threads which might be blocked in |port_wait|.
+    // Issuing too many packets is also harmless.
+    uint32_t n = atomic_load_explicit(&loop->active_threads, memory_order_acquire);
+    for (uint32_t i = 0u; i < n; i++) {
+        zx_port_packet_t packet = {
+            .key = KEY_CONTROL,
+            .type = ZX_PKT_TYPE_USER,
+            .status = ZX_OK};
+        zx_status_t status = zx_port_queue(loop->port, &packet);
+        ZX_ASSERT_MSG(status == ZX_OK, "zx_port_queue: status=%d", status);
+    }
+}
+
+zx_status_t async_loop_reset_quit(async_loop_t* loop) {
+    ZX_DEBUG_ASSERT(loop);
+
+    // Ensure that there are no active threads before resetting the quit state.
+    // This check is inherently racy but not dangerously so.  It's mainly a
+    // sanity check for client code so we can make a stronger statement about
+    // how |async_loop_reset_quit()| is supposed to be used.
+    uint32_t n = atomic_load_explicit(&loop->active_threads, memory_order_acquire);
+    if (n != 0)
+        return ZX_ERR_BAD_STATE;
+
+    async_loop_state_t expected_state = ASYNC_LOOP_QUIT;
+    if (atomic_compare_exchange_strong_explicit(&loop->state, &expected_state,
+                                                ASYNC_LOOP_RUNNABLE,
+                                                memory_order_acq_rel, memory_order_acquire)) {
+        return ZX_OK;
+    }
+
+    async_loop_state_t state = atomic_load_explicit(&loop->state, memory_order_acquire);
+    if (state == ASYNC_LOOP_RUNNABLE)
+        return ZX_OK;
+    return ZX_ERR_BAD_STATE;
+}
+
+async_loop_state_t async_loop_get_state(async_loop_t* loop) {
+    ZX_DEBUG_ASSERT(loop);
+
+    return atomic_load_explicit(&loop->state, memory_order_acquire);
+}
+
+zx_time_t async_loop_now(async_dispatcher_t* dispatcher) {
+    return zx_clock_get_monotonic();
+}
+
+static zx_status_t async_loop_begin_wait(async_dispatcher_t* async, async_wait_t* wait) {
+    async_loop_t* loop = (async_loop_t*)async;
+    ZX_DEBUG_ASSERT(loop);
+    ZX_DEBUG_ASSERT(wait);
+
+    if (atomic_load_explicit(&loop->state, memory_order_acquire) == ASYNC_LOOP_SHUTDOWN)
+        return ZX_ERR_BAD_STATE;
+
+    mtx_lock(&loop->lock);
+
+    zx_status_t status = zx_object_wait_async(
+        wait->object, loop->port, (uintptr_t)wait, wait->trigger, ZX_WAIT_ASYNC_ONCE);
+    if (status == ZX_OK) {
+        list_add_head(&loop->wait_list, wait_to_node(wait));
+    } else {
+        ZX_ASSERT_MSG(status == ZX_ERR_ACCESS_DENIED,
+                      "zx_object_wait_async: status=%d", status);
+    }
+
+    mtx_unlock(&loop->lock);
+    return status;
+}
+
+static zx_status_t async_loop_cancel_wait(async_dispatcher_t* async, async_wait_t* wait) {
+    async_loop_t* loop = (async_loop_t*)async;
+    ZX_DEBUG_ASSERT(loop);
+    ZX_DEBUG_ASSERT(wait);
+
+    // Note: We need to process cancelations even while the loop is being
+    // destroyed in case the client is counting on the handler not being
+    // invoked again past this point.
+
+    mtx_lock(&loop->lock);
+
+    // First, confirm that the wait is actually pending.
+    list_node_t* node = wait_to_node(wait);
+    if (!list_in_list(node)) {
+        mtx_unlock(&loop->lock);
+        return ZX_ERR_NOT_FOUND;
+    }
+
+    // Next, cancel the wait.  This may be racing with another thread that
+    // has read the wait's packet but not yet dispatched it.  So if we fail
+    // to cancel then we assume we lost the race.
+    zx_status_t status = zx_port_cancel(loop->port, wait->object,
+                                        (uintptr_t)wait);
+    if (status == ZX_OK) {
+        list_delete(node);
+    } else {
+        ZX_ASSERT_MSG(status == ZX_ERR_NOT_FOUND,
+                      "zx_port_cancel: status=%d", status);
+    }
+
+    mtx_unlock(&loop->lock);
+    return status;
+}
+
+static zx_status_t async_loop_post_task(async_dispatcher_t* async, async_task_t* task) {
+    async_loop_t* loop = (async_loop_t*)async;
+    ZX_DEBUG_ASSERT(loop);
+    ZX_DEBUG_ASSERT(task);
+
+    if (atomic_load_explicit(&loop->state, memory_order_acquire) == ASYNC_LOOP_SHUTDOWN)
+        return ZX_ERR_BAD_STATE;
+
+    mtx_lock(&loop->lock);
+
+    async_loop_insert_task_locked(loop, task);
+    if (!loop->dispatching_tasks &&
+        task_to_node(task)->prev == &loop->task_list) {
+        // Task inserted at head.  Earliest deadline changed.
+        async_loop_restart_timer_locked(loop);
+    }
+
+    mtx_unlock(&loop->lock);
+    return ZX_OK;
+}
+
+static zx_status_t async_loop_cancel_task(async_dispatcher_t* async, async_task_t* task) {
+    async_loop_t* loop = (async_loop_t*)async;
+    ZX_DEBUG_ASSERT(loop);
+    ZX_DEBUG_ASSERT(task);
+
+    // Note: We need to process cancelations even while the loop is being
+    // destroyed in case the client is counting on the handler not being
+    // invoked again past this point.  Also, the task we're removing here
+    // might be present in the dispatcher's |due_list| if it is pending
+    // dispatch instead of in the loop's |task_list| as usual.  The same
+    // logic works in both cases.
+
+    mtx_lock(&loop->lock);
+    list_node_t* node = task_to_node(task);
+    if (!list_in_list(node)) {
+        mtx_unlock(&loop->lock);
+        return ZX_ERR_NOT_FOUND;
+    }
+
+    // Determine whether the head task was canceled and following task has
+    // a later deadline.  If so, we will bump the timer along to that deadline.
+    bool must_restart = !loop->dispatching_tasks &&
+                        node->prev == &loop->task_list &&
+                        node->next != &loop->task_list &&
+                        node_to_task(node->next)->deadline > task->deadline;
+    list_delete(node);
+    if (must_restart)
+        async_loop_restart_timer_locked(loop);
+
+    mtx_unlock(&loop->lock);
+    return ZX_OK;
+}
+
+static zx_status_t async_loop_queue_packet(async_dispatcher_t* async, async_receiver_t* receiver,
+                                           const zx_packet_user_t* data) {
+    async_loop_t* loop = (async_loop_t*)async;
+    ZX_DEBUG_ASSERT(loop);
+    ZX_DEBUG_ASSERT(receiver);
+
+    if (atomic_load_explicit(&loop->state, memory_order_acquire) == ASYNC_LOOP_SHUTDOWN)
+        return ZX_ERR_BAD_STATE;
+
+    zx_port_packet_t packet = {
+        .key = (uintptr_t)receiver,
+        .type = ZX_PKT_TYPE_USER,
+        .status = ZX_OK};
+    if (data)
+        packet.user = *data;
+    return zx_port_queue(loop->port, &packet);
+}
+
+static zx_status_t async_loop_set_guest_bell_trap(
+    async_dispatcher_t* async, async_guest_bell_trap_t* trap,
+    zx_handle_t guest, zx_vaddr_t addr, size_t length) {
+    async_loop_t* loop = (async_loop_t*)async;
+    ZX_DEBUG_ASSERT(loop);
+    ZX_DEBUG_ASSERT(trap);
+
+    if (atomic_load_explicit(&loop->state, memory_order_acquire) == ASYNC_LOOP_SHUTDOWN)
+        return ZX_ERR_BAD_STATE;
+
+    zx_status_t status = zx_guest_set_trap(guest, ZX_GUEST_TRAP_BELL, addr,
+                                           length, loop->port, (uintptr_t)trap);
+    if (status != ZX_OK) {
+        ZX_ASSERT_MSG(status == ZX_ERR_ACCESS_DENIED ||
+                          status == ZX_ERR_ALREADY_EXISTS ||
+                          status == ZX_ERR_INVALID_ARGS ||
+                          status == ZX_ERR_OUT_OF_RANGE ||
+                          status == ZX_ERR_WRONG_TYPE,
+                      "zx_guest_set_trap: status=%d", status);
+    }
+    return status;
+}
+
+static zx_status_t async_loop_bind_exception_port(async_dispatcher_t* async,
+                                                  async_exception_t* exception) {
+    async_loop_t* loop = (async_loop_t*)async;
+    ZX_DEBUG_ASSERT(loop);
+    ZX_DEBUG_ASSERT(exception);
+
+    if (atomic_load_explicit(&loop->state, memory_order_acquire) == ASYNC_LOOP_SHUTDOWN)
+        return ZX_ERR_BAD_STATE;
+
+    mtx_lock(&loop->lock);
+
+    uint64_t key = (uintptr_t)(void*) exception;
+    zx_status_t status = zx_task_bind_exception_port(exception->task, loop->port,
+                                                     key, exception->options);
+    if (status == ZX_OK) {
+        list_add_head(&loop->exception_list, exception_to_node(exception));
+    }
+
+    mtx_unlock(&loop->lock);
+    return status;
+}
+
+static zx_status_t async_loop_unbind_exception_port(async_dispatcher_t* async,
+                                                    async_exception_t* exception) {
+    async_loop_t* loop = (async_loop_t*)async;
+    ZX_DEBUG_ASSERT(loop);
+    ZX_DEBUG_ASSERT(exception);
+
+    // Note: We need to process unbindings even while the loop is being
+    // destroyed in case the client is counting on the handler not being
+    // invoked again past this point.
+
+    mtx_lock(&loop->lock);
+
+    // First, confirm that the port is actually bound.
+    list_node_t* node = exception_to_node(exception);
+    if (!list_in_list(node)) {
+        mtx_unlock(&loop->lock);
+        return ZX_ERR_NOT_FOUND;
+    }
+
+    uint64_t key = (uintptr_t)(void*) exception;
+    zx_status_t status = zx_task_bind_exception_port(exception->task,
+                                                     ZX_HANDLE_INVALID, key, 0);
+
+    if (status == ZX_OK) {
+        list_delete(node);
+    }
+
+    mtx_unlock(&loop->lock);
+    return status;
+}
+
+static zx_status_t async_loop_resume_from_exception(async_dispatcher_t* async,
+                                                    async_exception_t* exception,
+                                                    zx_handle_t task,
+                                                    uint32_t options) {
+    async_loop_t* loop = (async_loop_t*)async;
+    ZX_DEBUG_ASSERT(loop);
+    ZX_DEBUG_ASSERT(exception);
+
+    if (atomic_load_explicit(&loop->state, memory_order_acquire) == ASYNC_LOOP_SHUTDOWN)
+        return ZX_ERR_BAD_STATE;
+
+    return zx_task_resume_from_exception(task, loop->port, options);
+}
+
+static void async_loop_insert_task_locked(async_loop_t* loop, async_task_t* task) {
+    // TODO(ZX-976): We assume that tasks are inserted in quasi-monotonic order and
+    // that insertion into the task queue will typically take no more than a few steps.
+    // If this assumption proves false and the cost of insertion becomes a problem, we
+    // should consider using a more efficient representation for maintaining order.
+    list_node_t* node;
+    for (node = loop->task_list.prev; node != &loop->task_list; node = node->prev) {
+        if (task->deadline >= node_to_task(node)->deadline)
+            break;
+    }
+    list_add_after(node, task_to_node(task));
+}
+
+static void async_loop_restart_timer_locked(async_loop_t* loop) {
+    zx_time_t deadline;
+    if (list_is_empty(&loop->due_list)) {
+        list_node_t* head = list_peek_head(&loop->task_list);
+        if (!head)
+            return;
+        async_task_t* task = node_to_task(head);
+        deadline = task->deadline;
+        if (deadline == ZX_TIME_INFINITE)
+            return;
+    } else {
+        // Fire now.
+        deadline = 0ULL;
+    }
+
+    zx_status_t status = zx_timer_set(loop->timer, deadline, 0);
+    ZX_ASSERT_MSG(status == ZX_OK, "zx_timer_set: status=%d", status);
+}
+
+static void async_loop_invoke_prologue(async_loop_t* loop) {
+    if (loop->config.prologue)
+        loop->config.prologue(loop, loop->config.data);
+}
+
+static void async_loop_invoke_epilogue(async_loop_t* loop) {
+    if (loop->config.epilogue)
+        loop->config.epilogue(loop, loop->config.data);
+}
+
+static int async_loop_run_thread(void* data) {
+    async_loop_t* loop = (async_loop_t*)data;
+    async_set_default_dispatcher(&loop->dispatcher);
+    async_loop_run(loop, ZX_TIME_INFINITE, false);
+    return 0;
+}
+
+zx_status_t async_loop_start_thread(async_loop_t* loop, const char* name, thrd_t* out_thread) {
+    ZX_DEBUG_ASSERT(loop);
+
+    // This check is inherently racy.  The client should not be racing shutdown
+    // with attemps to start new threads.  This is mainly a sanity check.
+    async_loop_state_t state = atomic_load_explicit(&loop->state, memory_order_acquire);
+    if (state == ASYNC_LOOP_SHUTDOWN)
+        return ZX_ERR_BAD_STATE;
+
+    thread_record_t* rec = calloc(1u, sizeof(thread_record_t));
+    if (!rec)
+        return ZX_ERR_NO_MEMORY;
+
+    if (thrd_create_with_name(&rec->thread, async_loop_run_thread, loop, name) != thrd_success) {
+        free(rec);
+        return ZX_ERR_NO_MEMORY;
+    }
+
+    mtx_lock(&loop->lock);
+    list_add_tail(&loop->thread_list, &rec->node);
+    mtx_unlock(&loop->lock);
+
+    if (out_thread)
+        *out_thread = rec->thread;
+    return ZX_OK;
+}
+
+void async_loop_join_threads(async_loop_t* loop) {
+    ZX_DEBUG_ASSERT(loop);
+
+    mtx_lock(&loop->lock);
+    for (;;) {
+        thread_record_t* rec = (thread_record_t*)list_remove_head(&loop->thread_list);
+        if (!rec)
+            break;
+
+        mtx_unlock(&loop->lock);
+        thrd_t thread = rec->thread;
+        free(rec);
+        int result = thrd_join(thread, NULL);
+        ZX_DEBUG_ASSERT(result == thrd_success);
+        mtx_lock(&loop->lock);
+    }
+    mtx_unlock(&loop->lock);
+}
diff --git a/pkg/async-loop/meta.json b/pkg/async-loop/meta.json
new file mode 100644
index 0000000..8a1eef7
--- /dev/null
+++ b/pkg/async-loop/meta.json
@@ -0,0 +1,22 @@
+{
+  "banjo_deps": [], 
+  "deps": [
+    "async", 
+    "async-default"
+  ], 
+  "fidl_deps": [], 
+  "files": [
+    "pkg/async-loop/loop.c", 
+    "pkg/async-loop/include/lib/async-loop/loop.h"
+  ], 
+  "headers": [
+    "pkg/async-loop/include/lib/async-loop/loop.h"
+  ], 
+  "include_dir": "pkg/async-loop/include", 
+  "name": "async-loop", 
+  "root": "pkg/async-loop", 
+  "sources": [
+    "pkg/async-loop/loop.c"
+  ], 
+  "type": "cc_source_library"
+}
\ No newline at end of file
diff --git a/pkg/async/include/lib/async/dispatcher.h b/pkg/async/include/lib/async/dispatcher.h
new file mode 100644
index 0000000..ff9b760
--- /dev/null
+++ b/pkg/async/include/lib/async/dispatcher.h
@@ -0,0 +1,125 @@
+// Copyright 2017 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef LIB_ASYNC_DISPATCHER_H_
+#define LIB_ASYNC_DISPATCHER_H_
+
+#include <zircon/compiler.h>
+#include <zircon/syscalls/port.h>
+#include <zircon/types.h>
+
+__BEGIN_CDECLS
+
+// Dispatcher interface for performing asynchronous operations.
+// There may be multiple implementations of this interface.
+typedef struct async_dispatcher async_dispatcher_t;
+
+// Forward declarations for asynchronous operation structures.
+typedef struct async_guest_bell_trap async_guest_bell_trap_t;
+typedef struct async_wait async_wait_t;
+typedef struct async_task async_task_t;
+typedef struct async_receiver async_receiver_t;
+typedef struct async_exception async_exception_t;
+
+// Private state owned by the asynchronous dispatcher.
+// This allows the dispatcher to associate a small amount of state with pending
+// asynchronous operations without having to allocate additional heap storage of
+// its own.
+//
+// Clients must initialize the contents of this structure to zero using
+// |ASYNC_STATE_INIT| or with calloc, memset, or a similar means.
+typedef struct {
+    uintptr_t reserved[2];
+} async_state_t;
+
+#define ASYNC_STATE_INIT \
+    { 0u, 0u }
+
+// Asynchronous dispatcher interface.
+//
+// Clients should not call into this interface directly: use the wrapper functions
+// declared in other header files, such as |async_begin_wait()| in <lib/async/wait.h>.
+// See the documentation of those functions for details about each method's purpose
+// and behavior.
+//
+// This interface consists of several groups of methods:
+//
+// - Timing: |now|
+// - Waiting for signals: |begin_wait|, |cancel_wait|
+// - Posting tasks: |post_task|, |cancel_task|
+// - Queuing packets: |queue_packet|
+// - Virtual machine operations: |set_guest_bell_trap|
+// - Exception handling: |bind_exception_port|, |unbind_exception_port|
+//
+// To preserve binary compatibility, each successive version of this interface
+// is guaranteed to be backwards-compatible with clients of earlier versions.
+// New methods must only be added by extending the structure at the end and
+// declaring a new version number.  Do not reorder the declarations or modify
+// existing versions.
+//
+// Implementations of this interface must provide valid (non-null) function pointers
+// for every method declared in the interface version they support.  Unsupported
+// methods must return |ZX_ERR_NOT_SUPPORTED| and have no other side-effects.
+// Furthermore, if an implementation supports one method of a group, such as |begin_wait|,
+// then it must also support the other methods of the group, such as |cancel_wait|.
+//
+// Many clients assume that the dispatcher interface is fully implemented and may
+// fail to work with dispatchers that do not support the methods they need.
+// Therefore general-purpose dispatcher implementations are encouraged to support
+// the whole interface to ensure broad compatibility.
+typedef uint32_t async_ops_version_t;
+
+#define ASYNC_OPS_V1 ((async_ops_version_t) 1)
+#define ASYNC_OPS_V2 ((async_ops_version_t) 2)
+
+typedef struct async_ops {
+    // The interface version number, e.g. |ASYNC_OPS_V2|.
+    async_ops_version_t version;
+
+    // Reserved for future expansion, set to zero.
+    uint32_t reserved;
+
+    // Operations supported by |ASYNC_OPS_V1|.
+    struct v1 {
+        // See |async_now()| for details.
+        zx_time_t (*now)(async_dispatcher_t* dispatcher);
+        // See |async_begin_wait()| for details.
+        zx_status_t (*begin_wait)(async_dispatcher_t* dispatcher, async_wait_t* wait);
+        // See |async_cancel_wait()| for details.
+        zx_status_t (*cancel_wait)(async_dispatcher_t* dispatcher, async_wait_t* wait);
+        // See |async_post_task()| for details.
+        zx_status_t (*post_task)(async_dispatcher_t* dispatcher, async_task_t* task);
+        // See |async_cancel_task()| for details.
+        zx_status_t (*cancel_task)(async_dispatcher_t* dispatcher, async_task_t* task);
+        // See |async_queue_packet()| for details.
+        zx_status_t (*queue_packet)(async_dispatcher_t* dispatcher, async_receiver_t* receiver,
+                                    const zx_packet_user_t* data);
+        // See |async_set_guest_bell_trap()| for details.
+        zx_status_t (*set_guest_bell_trap)(async_dispatcher_t* dispatcher, async_guest_bell_trap_t* trap,
+                                           zx_handle_t guest, zx_vaddr_t addr, size_t length);
+    } v1;
+
+    // Operations supported by |ASYNC_OPS_V2|, in addition to those in V1.
+    struct v2 {
+        // See |async_bind_exception_port()| for details.
+        zx_status_t (*bind_exception_port)(async_dispatcher_t* dispatcher,
+                                           async_exception_t* exception);
+        // See |async_unbind_exception_port()| for details.
+        zx_status_t (*unbind_exception_port)(async_dispatcher_t* dispatcher,
+                                             async_exception_t* exception);
+        // See |async_resume_from_exception()| for details.
+        zx_status_t (*resume_from_exception)(async_dispatcher_t* dispatcher,
+                                             async_exception_t* exception,
+                                             zx_handle_t task,
+                                             uint32_t options);
+    } v2;
+} async_ops_t;
+
+struct async_dispatcher {
+    const async_ops_t* ops;
+};
+
+__END_CDECLS
+
+#endif  // LIB_ASYNC_DISPATCHER_H_
diff --git a/pkg/async/include/lib/async/exception.h b/pkg/async/include/lib/async/exception.h
new file mode 100644
index 0000000..654a294
--- /dev/null
+++ b/pkg/async/include/lib/async/exception.h
@@ -0,0 +1,84 @@
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef LIB_ASYNC_EXCEPTION_H_
+#define LIB_ASYNC_EXCEPTION_H_
+
+#include <lib/async/dispatcher.h>
+
+__BEGIN_CDECLS
+
+// Handles receipt of packets containing exception reports.
+//
+// The |status| is |ZX_OK| if the packet was successfully delivered and |data|
+// contains the information from the packet, otherwise |data| is null.
+// The |status| is |ZX_ERR_CANCELED| if the dispatcher was shut down.
+typedef void(async_exception_handler_t)(async_dispatcher_t* dispatcher,
+                                        async_exception_t* exception,
+                                        zx_status_t status,
+                                        const zx_port_packet_t* report);
+
+// Holds content for an exception packet receiver and its handler.
+//
+// The client is responsible for retaining the structure in memory
+// (and unmodified) until all packets have been received by the handler or the
+// dispatcher shuts down.
+//
+// Multiple packets may be delivered to the same receiver concurrently.
+struct async_exception {
+    // Private state owned by the dispatcher, initialize to zero with |ASYNC_STATE_INIT|.
+    async_state_t state;
+
+    // The handler to invoke when a packet is received.
+    async_exception_handler_t* handler;
+
+    // The task we're watching.
+    zx_handle_t task;
+
+    // The options to pass to zx_task_bind_exception_port().
+    uint32_t options;
+};
+
+// Bind the async port to the task's exception port.
+//
+// Returns |ZX_OK| if task's exception port was successfully bound to.
+// Returns |ZX_ERR_BAD_STATE| if the dispatcher is shutting down.
+// Returns |ZX_ERR_NOT_SUPPORTED| if not supported by the dispatcher.
+// Other error values are possible. See the documentation for
+// |zx_task_bind_exception_port()|.
+//
+// This operation is thread-safe.
+zx_status_t async_bind_exception_port(async_dispatcher_t* dispatcher,
+                                      async_exception_t* exception);
+
+// Unbind the async port from |task|'s exception port.
+//
+// Returns |ZX_OK| if the task's exception port was successfully unbound.
+// Returns |ZX_ERR_NOT_FOUND| if the port is not bound.
+// Returns |ZX_ERR_NOT_SUPPORTED| if not supported by the dispatcher.
+// Other error values are possible. See the documentation for
+// |zx_task_bind_exception_port()|.
+//
+// This operation is thread-safe.
+zx_status_t async_unbind_exception_port(async_dispatcher_t* dispatcher,
+                                        async_exception_t* exception);
+
+// Resume |task| after having processed an exception for it.
+// |options| is passed to |zx_task_resume_from_exception()|.
+//
+// Returns |ZX_OK| if the task was resumed.
+// Returns |ZX_ERR_BAD_STATE| if the dispatcher is shutting down.
+// Returns |ZX_ERR_NOT_SUPPORTED| if not supported by the dispatcher.
+// Other error values are possible. See the documentation for
+// |zx_task_resume_from_exception()|.
+//
+// This operation is thread-safe.
+zx_status_t async_resume_from_exception(async_dispatcher_t* dispatcher,
+                                        async_exception_t* exception,
+                                        zx_handle_t task,
+                                        uint32_t options);
+
+__END_CDECLS
+
+#endif  // LIB_ASYNC_EXCEPTION_H_
diff --git a/pkg/async/include/lib/async/receiver.h b/pkg/async/include/lib/async/receiver.h
new file mode 100644
index 0000000..453df71
--- /dev/null
+++ b/pkg/async/include/lib/async/receiver.h
@@ -0,0 +1,52 @@
+// Copyright 2017 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef LIB_ASYNC_RECEIVER_H_
+#define LIB_ASYNC_RECEIVER_H_
+
+#include <lib/async/dispatcher.h>
+
+__BEGIN_CDECLS
+
+// Handles receipt of packets containing user supplied data.
+//
+// The |status| is |ZX_OK| if the packet was successfully delivered and |data|
+// contains the information from the packet, otherwise |data| is null.
+typedef void(async_receiver_handler_t)(async_dispatcher_t* dispatcher,
+                                       async_receiver_t* receiver,
+                                       zx_status_t status,
+                                       const zx_packet_user_t* data);
+
+// Holds content for a packet receiver and its handler.
+//
+// After successfully queuing packets to the receiver, the client is responsible
+// for retaining the structure in memory (and unmodified) until all packets have
+// been received by the handler or the dispatcher shuts down.  There is no way
+// to cancel a packet which has been queued.
+//
+// Multiple packets may be delivered to the same receiver concurrently.
+struct async_receiver {
+    // Private state owned by the dispatcher, initialize to zero with |ASYNC_STATE_INIT|.
+    async_state_t state;
+
+    // The handler to invoke when a packet is received.
+    async_receiver_handler_t* handler;
+};
+
+// Enqueues a packet of data for delivery to a receiver.
+//
+// The |data| will be copied into the packet.  May be NULL to create a
+// zero-initialized packet payload.
+//
+// Returns |ZX_OK| if the packet was successfully enqueued.
+// Returns |ZX_ERR_BAD_STATE| if the dispatcher is shutting down.
+// Returns |ZX_ERR_NOT_SUPPORTED| if not supported by the dispatcher.
+//
+// This operation is thread-safe.
+zx_status_t async_queue_packet(async_dispatcher_t* dispatcher, async_receiver_t* receiver,
+                               const zx_packet_user_t* data);
+
+__END_CDECLS
+
+#endif  // LIB_ASYNC_RECEIVER_H_
\ No newline at end of file
diff --git a/pkg/async/include/lib/async/task.h b/pkg/async/include/lib/async/task.h
new file mode 100644
index 0000000..ee0b295
--- /dev/null
+++ b/pkg/async/include/lib/async/task.h
@@ -0,0 +1,70 @@
+// Copyright 2017 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef LIB_ASYNC_TASK_H_
+#define LIB_ASYNC_TASK_H_
+
+#include <lib/async/dispatcher.h>
+
+__BEGIN_CDECLS
+
+// Handles execution of a posted task.
+//
+// The |status| is |ZX_OK| if the task's deadline elapsed and the task should run.
+// The |status| is |ZX_ERR_CANCELED| if the dispatcher was shut down before
+// the task's handler ran or the task was canceled.
+typedef void(async_task_handler_t)(async_dispatcher_t* dispatcher,
+                                   async_task_t* task,
+                                   zx_status_t status);
+
+// Holds context for a task and its handler.
+//
+// After successfully posting the task, the client is responsible for retaining
+// the structure in memory (and unmodified) until the task's handler runs, the task
+// is successfully canceled, or the dispatcher shuts down.  Thereafter, the task
+// may be posted again or destroyed.
+struct async_task {
+    // Private state owned by the dispatcher, initialize to zero with |ASYNC_STATE_INIT|.
+    async_state_t state;
+
+    // The task's handler function.
+    async_task_handler_t* handler;
+
+    // The task's deadline must be expressed in the time base used by the asynchronous
+    // dispatcher (usually |ZX_CLOCK_MONOTONIC| except in unit tests).
+    // See |async_now()| for details.
+    zx_time_t deadline;
+};
+
+// Posts a task to run on or after its deadline following all posted
+// tasks with lesser or equal deadlines.
+//
+// The task's handler will be invoked exactly once unless the task is canceled.
+// When the dispatcher is shutting down (being destroyed), the handlers of
+// all remaining tasks will be invoked with a status of |ZX_ERR_CANCELED|.
+//
+// Returns |ZX_OK| if the task was successfully posted.
+// Returns |ZX_ERR_BAD_STATE| if the dispatcher is shutting down.
+// Returns |ZX_ERR_NOT_SUPPORTED| if not supported by the dispatcher.
+//
+// This operation is thread-safe.
+zx_status_t async_post_task(async_dispatcher_t* dispatcher, async_task_t* task);
+
+// Cancels the task associated with |task|.
+//
+// If successful, the task's handler will not run.
+//
+// Returns |ZX_OK| if the task was pending and it has been successfully
+// canceled; its handler will not run again and can be released immediately.
+// Returns |ZX_ERR_NOT_FOUND| if there was no pending task either because it
+// already ran, had not been posted, or has been dequeued and is pending
+// execution (perhaps on another thread).
+// Returns |ZX_ERR_NOT_SUPPORTED| if not supported by the dispatcher.
+//
+// This operation is thread-safe.
+zx_status_t async_cancel_task(async_dispatcher_t* dispatcher, async_task_t* task);
+
+__END_CDECLS
+
+#endif  // LIB_ASYNC_TASK_H_
\ No newline at end of file
diff --git a/pkg/async/include/lib/async/time.h b/pkg/async/include/lib/async/time.h
new file mode 100644
index 0000000..fe62cd5
--- /dev/null
+++ b/pkg/async/include/lib/async/time.h
@@ -0,0 +1,19 @@
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef LIB_ASYNC_TIME_H_
+#define LIB_ASYNC_TIME_H_
+
+#include <lib/async/dispatcher.h>
+
+__BEGIN_CDECLS
+
+// Returns the current time in the dispatcher's timebase.
+// For most loops, this is generally obtained from |ZX_CLOCK_MONOTONIC|
+// but certain loops may use a different tiembase, notably for testing.
+zx_time_t async_now(async_dispatcher_t* dispatcher);
+
+__END_CDECLS
+
+#endif  // LIB_ASYNC_TIME_H_
\ No newline at end of file
diff --git a/pkg/async/include/lib/async/trap.h b/pkg/async/include/lib/async/trap.h
new file mode 100644
index 0000000..814d9ef
--- /dev/null
+++ b/pkg/async/include/lib/async/trap.h
@@ -0,0 +1,56 @@
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef LIB_ASYNC_TRAP_H_
+#define LIB_ASYNC_TRAP_H_
+
+#include <lib/async/dispatcher.h>
+
+__BEGIN_CDECLS
+
+// Handles an asynchronous trap access.
+//
+// The |status| is |ZX_OK| if the bell was received and |bell| contains the
+// information from the packet, otherwise |bell| is null.
+typedef void(async_guest_bell_trap_handler_t)(async_dispatcher_t* dispatcher,
+                                              async_guest_bell_trap_t* trap,
+                                              zx_status_t status,
+                                              const zx_packet_guest_bell_t* bell);
+
+// Holds context for a bell trap and its handler.
+//
+// After successfully posting setting the trap, the client is responsible for retaining
+// the structure in memory (and unmodified) until the guest has been destroyed or the
+// dispatcher shuts down.  There is no way to cancel a trap which has been set.
+struct async_guest_bell_trap {
+    // Private state owned by the dispatcher, initialize to zero with |ASYNC_STATE_INIT|.
+    async_state_t state;
+
+    // The handler to invoke to handle the trap access.
+    async_guest_bell_trap_handler_t* handler;
+};
+
+// Sets a bell trap in the guest to be handled asynchronously via a handler.
+//
+// |guest| is the handle of the guest the trap will be set on.
+// |addr| is the base address for the trap in the guest's physical address space.
+// |length| is the size of the trap in the guest's physical address space.
+//
+// Returns |ZX_OK| if the trap was successfully set.
+// Returns |ZX_ERR_ACCESS_DENIED| if the guest does not have |ZX_RIGHT_WRITE|.
+// Returns |ZX_ERR_ALREADY_EXISTS| if a bell trap with the same |addr| exists.
+// Returns |ZX_ERR_INVALID_ARGS| if |addr| or |length| are invalid.
+// Returns |ZX_ERR_OUT_OF_RANGE| if |addr| or |length| are out of range of the
+// address space.
+// Returns |ZX_ERR_WRONG_TYPE| if |guest| is not a handle to a guest.
+// Returns |ZX_ERR_BAD_STATE| if the dispatcher is shutting down.
+// Returns |ZX_ERR_NOT_SUPPORTED| if not supported by the dispatcher.
+//
+// This operation is thread-safe.
+zx_status_t async_set_guest_bell_trap(async_dispatcher_t* dispatcher, async_guest_bell_trap_t* trap,
+                                      zx_handle_t guest, zx_vaddr_t addr, size_t length);
+
+__END_CDECLS
+
+#endif  // LIB_ASYNC_TRAP_H_
\ No newline at end of file
diff --git a/pkg/async/include/lib/async/wait.h b/pkg/async/include/lib/async/wait.h
new file mode 100644
index 0000000..d359979
--- /dev/null
+++ b/pkg/async/include/lib/async/wait.h
@@ -0,0 +1,74 @@
+// Copyright 2017 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef LIB_ASYNC_WAIT_H_
+#define LIB_ASYNC_WAIT_H_
+
+#include <lib/async/dispatcher.h>
+
+__BEGIN_CDECLS
+
+// Handles completion of asynchronous wait operations.
+//
+// The |status| is |ZX_OK| if the wait was satisfied and |signal| is non-null.
+// The |status| is |ZX_ERR_CANCELED| if the dispatcher was shut down before
+// the task's handler ran or the task was canceled.
+typedef void(async_wait_handler_t)(async_dispatcher_t* dispatcher,
+                                   async_wait_t* wait,
+                                   zx_status_t status,
+                                   const zx_packet_signal_t* signal);
+
+// Holds context for an asynchronous wait operation and its handler.
+//
+// After successfully beginning the wait, the client is responsible for retaining
+// the structure in memory (and unmodified) until the wait's handler runs, the wait
+// is successfully canceled, or the dispatcher shuts down.  Thereafter, the wait
+// may be started begun or destroyed.
+struct async_wait {
+    // Private state owned by the dispatcher, initialize to zero with |ASYNC_STATE_INIT|.
+    async_state_t state;
+
+    // The wait's handler function.
+    async_wait_handler_t* handler;
+
+    // The object to wait for signals on.
+    zx_handle_t object;
+
+    // The set of signals to wait for.
+    zx_signals_t trigger;
+};
+
+// Begins asynchronously waiting for an object to receive one or more signals
+// specified in |wait|.  Invokes the handler when the wait completes.
+//
+// The wait's handler will be invoked exactly once unless the wait is canceled.
+// When the dispatcher is shutting down (being destroyed), the handlers of
+// all remaining waits will be invoked with a status of |ZX_ERR_CANCELED|.
+//
+// Returns |ZX_OK| if the wait was successfully begun.
+// Returns |ZX_ERR_ACCESS_DENIED| if the object does not have |ZX_RIGHT_WAIT|.
+// Returns |ZX_ERR_BAD_STATE| if the dispatcher is shutting down.
+// Returns |ZX_ERR_NOT_SUPPORTED| if not supported by the dispatcher.
+//
+// This operation is thread-safe.
+zx_status_t async_begin_wait(async_dispatcher_t* dispatcher, async_wait_t* wait);
+
+// Cancels the wait associated with |wait|.
+//
+// If successful, the wait's handler will not run.
+//
+// Returns |ZX_OK| if the wait was pending and it has been successfully
+// canceled; its handler will not run again and can be released immediately.
+// Returns |ZX_ERR_NOT_FOUND| if there was no pending wait either because it
+// already completed, had not been started, or its completion packet has been
+// dequeued from the port and is pending delivery to its handler (perhaps on
+// another thread).
+// Returns |ZX_ERR_NOT_SUPPORTED| if not supported by the dispatcher.
+//
+// This operation is thread-safe.
+zx_status_t async_cancel_wait(async_dispatcher_t* dispatcher, async_wait_t* wait);
+
+__END_CDECLS
+
+#endif  // LIB_ASYNC_WAIT_H_
\ No newline at end of file
diff --git a/pkg/async/meta.json b/pkg/async/meta.json
new file mode 100644
index 0000000..31913e9
--- /dev/null
+++ b/pkg/async/meta.json
@@ -0,0 +1,31 @@
+{
+  "banjo_deps": [], 
+  "deps": [], 
+  "fidl_deps": [], 
+  "files": [
+    "pkg/async/ops.c", 
+    "pkg/async/include/lib/async/dispatcher.h", 
+    "pkg/async/include/lib/async/exception.h", 
+    "pkg/async/include/lib/async/receiver.h", 
+    "pkg/async/include/lib/async/task.h", 
+    "pkg/async/include/lib/async/time.h", 
+    "pkg/async/include/lib/async/trap.h", 
+    "pkg/async/include/lib/async/wait.h"
+  ], 
+  "headers": [
+    "pkg/async/include/lib/async/dispatcher.h", 
+    "pkg/async/include/lib/async/exception.h", 
+    "pkg/async/include/lib/async/receiver.h", 
+    "pkg/async/include/lib/async/task.h", 
+    "pkg/async/include/lib/async/time.h", 
+    "pkg/async/include/lib/async/trap.h", 
+    "pkg/async/include/lib/async/wait.h"
+  ], 
+  "include_dir": "pkg/async/include", 
+  "name": "async", 
+  "root": "pkg/async", 
+  "sources": [
+    "pkg/async/ops.c"
+  ], 
+  "type": "cc_source_library"
+}
\ No newline at end of file
diff --git a/pkg/async/ops.c b/pkg/async/ops.c
new file mode 100644
index 0000000..e3b1d6d
--- /dev/null
+++ b/pkg/async/ops.c
@@ -0,0 +1,62 @@
+// Copyright 2017 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <lib/async/receiver.h>
+#include <lib/async/task.h>
+#include <lib/async/time.h>
+#include <lib/async/trap.h>
+#include <lib/async/wait.h>
+
+zx_time_t async_now(async_dispatcher_t* dispatcher) {
+    return dispatcher->ops->v1.now(dispatcher);
+}
+
+zx_status_t async_begin_wait(async_dispatcher_t* dispatcher, async_wait_t* wait) {
+    return dispatcher->ops->v1.begin_wait(dispatcher, wait);
+}
+
+zx_status_t async_cancel_wait(async_dispatcher_t* dispatcher, async_wait_t* wait) {
+    return dispatcher->ops->v1.cancel_wait(dispatcher, wait);
+}
+
+zx_status_t async_post_task(async_dispatcher_t* dispatcher, async_task_t* task) {
+    return dispatcher->ops->v1.post_task(dispatcher, task);
+}
+
+zx_status_t async_cancel_task(async_dispatcher_t* dispatcher, async_task_t* task) {
+    return dispatcher->ops->v1.cancel_task(dispatcher, task);
+}
+
+zx_status_t async_queue_packet(async_dispatcher_t* dispatcher, async_receiver_t* receiver,
+                               const zx_packet_user_t* data) {
+    return dispatcher->ops->v1.queue_packet(dispatcher, receiver, data);
+}
+
+zx_status_t async_set_guest_bell_trap(async_dispatcher_t* dispatcher, async_guest_bell_trap_t* trap,
+                                      zx_handle_t guest, zx_vaddr_t addr, size_t length) {
+    return dispatcher->ops->v1.set_guest_bell_trap(dispatcher, trap, guest, addr, length);
+}
+
+zx_status_t async_bind_exception_port(async_dispatcher_t* dispatcher,
+                                      async_exception_t* exception) {
+    if (dispatcher->ops->version < ASYNC_OPS_V2)
+        return ZX_ERR_NOT_SUPPORTED;
+    return dispatcher->ops->v2.bind_exception_port(dispatcher, exception);
+}
+
+zx_status_t async_unbind_exception_port(async_dispatcher_t* dispatcher,
+                                        async_exception_t* exception) {
+    if (dispatcher->ops->version < ASYNC_OPS_V2)
+        return ZX_ERR_NOT_SUPPORTED;
+    return dispatcher->ops->v2.unbind_exception_port(dispatcher, exception);
+}
+
+zx_status_t async_resume_from_exception(async_dispatcher_t* dispatcher,
+                                        async_exception_t* exception,
+                                        zx_handle_t task,
+                                        uint32_t options) {
+    if (dispatcher->ops->version < ASYNC_OPS_V2)
+        return ZX_ERR_NOT_SUPPORTED;
+    return dispatcher->ops->v2.resume_from_exception(dispatcher, exception, task, options);
+}
diff --git a/pkg/fdio/include/lib/fdio/debug.h b/pkg/fdio/include/lib/fdio/debug.h
new file mode 100644
index 0000000..22acfb6
--- /dev/null
+++ b/pkg/fdio/include/lib/fdio/debug.h
@@ -0,0 +1,20 @@
+// Copyright 2016 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#pragma once
+
+#include <stdio.h>
+#include <zircon/compiler.h>
+
+__BEGIN_CDECLS
+
+// per-file chatty debug macro
+#define xprintf(fmt, args...)                                                                      \
+    do {                                                                                           \
+        if (ZXDEBUG) {                                                                             \
+            printf("%s:%d: " fmt, __FILE__, __LINE__, ##args);                                     \
+        }                                                                                          \
+    } while (0)
+
+__END_CDECLS
diff --git a/pkg/fdio/include/lib/fdio/io.h b/pkg/fdio/include/lib/fdio/io.h
new file mode 100644
index 0000000..b567cf4
--- /dev/null
+++ b/pkg/fdio/include/lib/fdio/io.h
@@ -0,0 +1,62 @@
+// Copyright 2016 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#pragma once
+
+#include <limits.h>
+#include <poll.h>
+#include <stdbool.h>
+#include <unistd.h> // for ssize_t
+
+#include <zircon/types.h>
+#include <zircon/compiler.h>
+
+#include <lib/fdio/limits.h>
+
+// flag on handle args in processargs
+// instructing that this fd should be dup'd to 0/1/2
+// and be used for all of stdio
+#define FDIO_FLAG_USE_FOR_STDIO 0x8000
+
+// events for fdio_wait_fd()
+#define FDIO_EVT_READABLE POLLIN
+#define FDIO_EVT_WRITABLE POLLOUT
+#define FDIO_EVT_ERROR POLLERR
+#define FDIO_EVT_PEER_CLOSED POLLRDHUP
+#define FDIO_EVT_ALL (POLLIN | POLLOUT | POLLERR | POLLRDHUP)
+
+__BEGIN_CDECLS
+
+// wait until one or more events are pending
+zx_status_t fdio_wait_fd(int fd, uint32_t events, uint32_t* pending, zx_time_t deadline);
+
+// create a fd that works with wait APIs (epoll, select, etc.) from a handle
+// and expected signals (signals_in/signals_out correspond to POLLIN/POLLOUT
+// events respectively). the handle will be closed when the fd is closed, unless
+// shared_handle is true.
+int fdio_handle_fd(zx_handle_t h, zx_signals_t signals_in, zx_signals_t signals_out, bool shared_handle);
+
+// invoke a raw fdio ioctl
+ssize_t fdio_ioctl(int fd, int op, const void* in_buf, size_t in_len, void* out_buf, size_t out_len);
+
+// create a pipe, installing one half in a fd, returning the other
+// for transport to another process
+zx_status_t fdio_pipe_half(zx_handle_t* handle, uint32_t* type);
+
+// Get a read-only VMO containing the whole contents of the file.
+// This function creates a clone of the underlying VMO when possible, falling
+// back to eagerly reading the contents into a freshly-created VMO.
+zx_status_t fdio_get_vmo_copy(int fd, zx_handle_t* out_vmo);
+
+// Gets a read-only VMO containing a clone of the underlying VMO.
+// This function will fail rather than copying the contents if it cannot clone.
+zx_status_t fdio_get_vmo_clone(int fd, zx_handle_t* out_vmo);
+
+// Get a read-only handle to the exact VMO used by the file system server to
+// represent the file. This function fails if the server does not have an exact
+// VMO representation of the file (e.g., if fdio_get_vmo would need to copy
+// or clone data into a new VMO).
+zx_status_t fdio_get_vmo_exact(int fd, zx_handle_t* out_vmo);
+
+__END_CDECLS
diff --git a/pkg/fdio/include/lib/fdio/limits.h b/pkg/fdio/include/lib/fdio/limits.h
new file mode 100644
index 0000000..d6c5b68
--- /dev/null
+++ b/pkg/fdio/include/lib/fdio/limits.h
@@ -0,0 +1,23 @@
+// Copyright 2017 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#pragma once
+
+#include <limits.h>
+
+// Maximum number of fds per process.
+#define FDIO_MAX_FD 256
+
+// Maximum handles used in open/clone/create.
+#define FDIO_MAX_HANDLES 3
+
+// fdio_ops_t's read/write are able to do io of
+// at least this size.
+#define FDIO_CHUNK_SIZE 8192
+
+// Maximum size for an ioctl input.
+#define FDIO_IOCTL_MAX_INPUT 1024
+
+// Maximum length of a filename.
+#define FDIO_MAX_FILENAME NAME_MAX
diff --git a/pkg/fdio/include/lib/fdio/namespace.h b/pkg/fdio/include/lib/fdio/namespace.h
new file mode 100644
index 0000000..dcd7043
--- /dev/null
+++ b/pkg/fdio/include/lib/fdio/namespace.h
@@ -0,0 +1,95 @@
+// Copyright 2017 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#pragma once
+
+#include <stdint.h>
+
+#include <zircon/compiler.h>
+#include <zircon/types.h>
+
+__BEGIN_CDECLS;
+
+typedef struct fdio_namespace fdio_ns_t;
+
+
+// Create a new, empty namespace
+zx_status_t fdio_ns_create(fdio_ns_t** out);
+
+// Destroy and deallocate a namespace
+// Will fail (ZX_ERR_BAD_STATE) if the namespace is in use.
+zx_status_t fdio_ns_destroy(fdio_ns_t* ns);
+
+// Create a new directory within a namespace, bound to the
+// directory-protocol-compatible handle h
+// The path must be an absolute path, like "/x/y/z", containing
+// no "." nor ".." entries.  It is relative to the root of the
+// namespace.
+//
+// The handle is not closed on failure.
+//
+// Will fail with ZX_ERR_BAD_STATE if the namespace is in use.
+zx_status_t fdio_ns_bind(fdio_ns_t* ns, const char* path, zx_handle_t h);
+
+// Create a new directory within a namespace, bound to the
+// directory referenced by the file descriptor fd.
+// The path must be an absolute path, like "/x/y/z", containing
+// no "." nor ".." entries.  It is relative to the root of the
+// namespace.
+//
+// The fd is not closed on success or failure.
+// Closing the fd after success does not affect namespace.
+//
+// Failures:
+// ZX_ERR_BAD_STATE: Namespace is already in use and immutable.
+// ZX_ERR_ALREADY_EXISTS: There is already a mounted directory there.
+// ZX_ERR_NOT_SUPPORTED: This path would shadow a mounted directory.
+zx_status_t fdio_ns_bind_fd(fdio_ns_t* ns, const char* path, int fd);
+
+// Open the root directory of the namespace as a file descriptor
+int fdio_ns_opendir(fdio_ns_t* ns);
+
+// chdir to / in the provided namespace
+zx_status_t fdio_ns_chdir(fdio_ns_t* ns);
+
+// Replace the fdio "global" namespace with the provided namespace
+zx_status_t fdio_ns_install(fdio_ns_t* ns);
+
+// Retrieve the fdio "global" namespace (if any).
+zx_status_t fdio_ns_get_installed(fdio_ns_t** ns);
+
+typedef struct fdio_flat_namespace {
+    size_t count;
+    zx_handle_t* handle;
+    uint32_t* type;
+    const char* const* path;
+} fdio_flat_namespace_t;
+
+// On success the caller takes ownership of a fdio_flat_namespace_t
+// containing a flat representation of the exported namespace (the
+// one provided in 'ns' or the active root namespace, respectively.)
+// The handles are CLONEs of the handles in the namespace and also
+// belong to the caller.
+// The whole data structure can be released with free(), keeping in
+// mind that the handles should be used or closed first.
+zx_status_t fdio_ns_export(fdio_ns_t* ns, fdio_flat_namespace_t** out);
+zx_status_t fdio_ns_export_root(fdio_flat_namespace_t** out);
+
+// Attempt to connect to a service through the namespace.
+// The handle is always consumed.  It will be closed on error
+// or passed to the remote service on success.
+// The path must be an absolute path starting with / and containing
+// no ".." or "." or empty segments.
+zx_status_t fdio_ns_connect(fdio_ns_t* ns, const char* path,
+                            uint32_t zxflags, zx_handle_t h);
+
+// Attempt a pipelined open through a namespace.
+// Success only indicates that the open was sent.
+// If the remote fails, the returned handle's peer will be closed.
+// The path must be an absolute path starting with / and containing
+// no ".." or "." or empty segments.
+zx_status_t fdio_ns_open(fdio_ns_t* ns, const char* path,
+                         uint32_t zxflags, zx_handle_t* out);
+
+__END_CDECLS;
diff --git a/pkg/fdio/include/lib/fdio/private.h b/pkg/fdio/include/lib/fdio/private.h
new file mode 100644
index 0000000..2ceee14
--- /dev/null
+++ b/pkg/fdio/include/lib/fdio/private.h
@@ -0,0 +1,22 @@
+// Copyright 2017 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#pragma once
+
+#include <zircon/compiler.h>
+#include <zircon/types.h>
+#include <stdint.h>
+
+__BEGIN_CDECLS;
+
+// WARNING: These APIs are subject to change
+
+// __fdio_cleanpath cleans an input path, placing the output
+// in out, which is a buffer of at least "PATH_MAX" bytes.
+//
+// 'outlen' returns the length of the path placed in out, and 'is_dir'
+// is set to true if the returned path must be a directory.
+zx_status_t __fdio_cleanpath(const char* in, char* out, size_t* outlen, bool* is_dir);
+
+__END_CDECLS;
diff --git a/pkg/fdio/include/lib/fdio/spawn.h b/pkg/fdio/include/lib/fdio/spawn.h
new file mode 100644
index 0000000..94a656d
--- /dev/null
+++ b/pkg/fdio/include/lib/fdio/spawn.h
@@ -0,0 +1,217 @@
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#pragma once
+
+#include <zircon/compiler.h>
+#include <zircon/types.h>
+
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdint.h>
+
+__BEGIN_CDECLS
+
+// The |fdio_spawn| and |fdio_spawn_etc| functions allow some or all of the
+// environment of the running process to be shared with the process being
+// spawned.
+
+// Provides the spawned process with the job in which the process was created.
+//
+// The spawned process receives the job using the |PA_JOB_DEFAULT| process
+// argument.
+#define FDIO_SPAWN_CLONE_JOB ((uint32_t)0x0001u)
+
+// Provides the spawned process with the shared library loader resolved via
+// fuchsia.process.Resolver (if resolved), or that which is used by this
+// process.
+//
+// The shared library loader is passed as |PA_LDSVC_LOADER|.
+#define FDIO_SPAWN_DEFAULT_LDSVC ((uint32_t)0x0002u)
+// FDIO_SPAWN_CLONE_LDSVC is the same as FDIO_SPAWN_DEFAULT_LDSVC.
+// TODO(ZX-3031): this name is deprecated.
+#define FDIO_SPAWN_CLONE_LDSVC ((uint32_t)0x0002u)
+
+// Clones the filesystem namespace into the spawned process.
+#define FDIO_SPAWN_CLONE_NAMESPACE ((uint32_t)0x0004u)
+
+// Clones file descriptors 0, 1, and 2 into the spawned process.
+//
+// Skips any of these file descriptors that are closed without generating an
+// error.
+#define FDIO_SPAWN_CLONE_STDIO ((uint32_t)0x0008u)
+
+// Clones the environment into the spawned process.
+#define FDIO_SPAWN_CLONE_ENVIRON ((uint32_t)0x0010u)
+
+// Clones all of the above into the spawned process.
+#define FDIO_SPAWN_CLONE_ALL ((uint32_t)0xFFFFu)
+
+// Spawn a process in the given job.
+//
+// The program for the process is loaded from the given |path| and passed |argv|.
+// The aspects of this process' environment indicated by |flags| are shared with
+// the process. If the target program begins with |#!resolve | then the binary is
+// resolved by url via |fuchsia.process.Resolver|.
+//
+// The |argv| array must be terminated with a null pointer.
+//
+// If |job| is |ZX_HANDLE_INVALID|, then the process is spawned in
+// |zx_job_default()|. Does not take ownership of |job|.
+//
+// Upon success, |process_out| will be a handle to the process.
+zx_status_t fdio_spawn(zx_handle_t job,
+                       uint32_t flags,
+                       const char* path,
+                       const char* const* argv,
+                       zx_handle_t* process_out);
+
+// The |fdio_spawn_etc| function allows the running process to control the file
+// descriptor table in the process being spawned.
+
+// Duplicate a descriptor |local_fd| into |target_fd| in the spawned process.
+//
+// Uses the |fd| entry in the |fdio_spawn_action_t| union.
+#define FDIO_SPAWN_ACTION_CLONE_FD ((uint32_t)0x0001u)
+
+// Transfer local descriptor |local_fd| into |target_fd| in the spawned process.
+//
+// This action will fail if |local_fd| is not a valid |local_fd|, if |local_fd|
+// has been duplicated, if |local_fd| is being used in an io operation, or if
+// |local_fd| does not support this operation.
+//
+// From the point of view of the calling process, the |local_fd| will appear to
+// have been closed, regardless of whether the |fdio_spawn_etc| call succeeds.
+//
+// Uses the |fd| entry in the |fdio_spawn_action_t| union.
+#define FDIO_SPAWN_ACTION_TRANSFER_FD ((uint32_t)0x0002u)
+
+// Add the given entry to the namespace of the spawned process.
+//
+// If |FDIO_SPAWN_CLONE_NAMESPACE| is specified via |flags|, the namespace entry
+// is added to the cloned namespace from the calling process.
+//
+// The given handle will be closed regardless of whether the |fdio_spawn_etc|
+// call succeeds.
+//
+// Uses the |ns| entry in the |fdio_spawn_action_t| union.
+#define FDIO_SPAWN_ACTION_ADD_NS_ENTRY ((uint32_t)0x0003u)
+
+// Add the given handle to the process arguments of the spawned process.
+//
+// The given handle will be closed regardless of whether the |fdio_spawn_etc|
+// call succeeds.
+//
+// Uses the |h| entry in the |fdio_spawn_action_t| union.
+#define FDIO_SPAWN_ACTION_ADD_HANDLE ((uint32_t)0x0004u)
+
+// Sets the name of the spawned process to the given name.
+//
+// Overrides the default of use the first argument to name the process.
+//
+// Uses the |name| entry in the |fdio_spawn_action_t| union.
+#define FDIO_SPAWN_ACTION_SET_NAME ((uint32_t)0x0005u)
+
+// Instructs |fdio_spawn_etc| which actions to take.
+typedef struct fdio_spawn_action fdio_spawn_action_t;
+struct fdio_spawn_action {
+    // The action to take.
+    //
+    // See |FDIO_SPAWN_ACTION_*| above. If |action| is invalid, the action will
+    // be ignored (rather than generate an error).
+    uint32_t action;
+    union {
+        struct {
+            // The file descriptor in this process to clone or transfer.
+            int local_fd;
+
+            // The file descriptor in the spawned process that will receive the
+            // clone or transfer.
+            int target_fd;
+        } fd;
+        struct {
+            // The prefix in which to install the given handle in the namespace
+            // of the spawned process.
+            const char* prefix;
+
+            // The handle to install with the given prefix in the namespace of
+            // the spawned process.
+            zx_handle_t handle;
+        } ns;
+        struct {
+            // The process argument identifier of the handle to pass to the
+            // spawned process.
+            uint32_t id;
+
+            // The handle to pass to the process on startup.
+            zx_handle_t handle;
+        } h;
+        struct {
+            // The name to assign to the spawned process.
+            const char* data;
+        } name;
+    };
+};
+
+// The maximum size for error messages from |fdio_spawn_etc|.
+//
+// Including the null terminator.
+#define FDIO_SPAWN_ERR_MSG_MAX_LENGTH ((size_t)1024u)
+
+// Spawn a process in the given job.
+//
+// The binary for the process is loaded from the given |path| and passed |argv|.
+// The aspects of this process' environment indicated by |clone| are shared with
+// the process.
+//
+// The spawned process is also given |environ| as its environment and the given
+// |actions| are applied when creating the process.
+//
+// The |argv| array must be terminated with a null pointer.
+//
+// If non-null, the |environ| array must be terminated with a null pointer.
+//
+// If non-null, the |err_msg_out| buffer must have space for
+// |FDIO_SPAWN_ERR_MSG_MAX_LENGTH| bytes.
+//
+// If both |FDIO_SPAWN_CLONE_ENVIRON| and |environ| are specified, then the
+// spawned process is given |environ| as its environment. If both
+// |FDIO_SPAWN_CLONE_STDIO| and |actions| that target any of fds 0, 1, and 2 are
+// specified, then the actions that target those fds will control their
+// semantics in the spawned process.
+//
+// If |job| is |ZX_HANDLE_INVALID|, then the process is spawned in
+// |zx_job_default()|. Does not take ownership of |job|.
+//
+// Upon success, |process_out| will be a handle to the process. Upon failure, if
+// |err_msg_out| is not null, an error message will be we written to
+// |err_msg_out|, including a null terminator.
+zx_status_t fdio_spawn_etc(zx_handle_t job,
+                           uint32_t flags,
+                           const char* path,
+                           const char* const* argv,
+                           const char* const* environ,
+                           size_t action_count,
+                           const fdio_spawn_action_t* actions,
+                           zx_handle_t* process_out,
+                           char err_msg_out[FDIO_SPAWN_ERR_MSG_MAX_LENGTH]);
+
+// Spawn a process using the given executable in the given job.
+//
+// See |fdio_spawn_etc| for details. Rather than loading the binary for the
+// process from a path, this function receives the binary as the contents of a
+// vmo.
+//
+// Always consumes |executable_vmo|.
+zx_status_t fdio_spawn_vmo(zx_handle_t job,
+                           uint32_t flags,
+                           zx_handle_t executable_vmo,
+                           const char* const* argv,
+                           const char* const* environ,
+                           size_t action_count,
+                           const fdio_spawn_action_t* actions,
+                           zx_handle_t* process_out,
+                           char err_msg_out[FDIO_SPAWN_ERR_MSG_MAX_LENGTH]);
+
+__END_CDECLS
diff --git a/pkg/fdio/include/lib/fdio/unsafe.h b/pkg/fdio/include/lib/fdio/unsafe.h
new file mode 100644
index 0000000..c0f7e41
--- /dev/null
+++ b/pkg/fdio/include/lib/fdio/unsafe.h
@@ -0,0 +1,65 @@
+// Copyright 2017 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#pragma once
+
+#include <zircon/compiler.h>
+#include <zircon/types.h>
+#include <stdint.h>
+
+__BEGIN_CDECLS;
+
+// WARNING: These interfaces exist to allow integration of fdio file
+// descriptors with handle-centric message loops.  If used incorrectly
+// they can seriously mess up the state of fdio, fds, etc.
+
+typedef struct fdio fdio_t;
+
+// This looks up a file descriptor, and if it exists,
+// upreferences the fdio_t under it and returns that.
+// fdio_unsafe_release() must be called later to release
+// the reference.
+//
+// If the fd does not exist, it returns NULL
+fdio_t* fdio_unsafe_fd_to_io(int fd);
+
+// Returns the handle corresponding to the underlying fdio,
+// if there is one. Returns ZX_HANDLE_INVALID otherwise.
+//
+// Since this handle is borrowed from the underlying fdio_t, it
+// is unsafe to close it or use it after fdio_unsafe_release is called.
+zx_handle_t fdio_unsafe_borrow_channel(fdio_t* io);
+
+// Releases a reference on a fdio_t.  Used to "return"
+// a fdio_t obtained from fdio_unsafe_fd_to_io() when you're
+// done with it.
+void fdio_unsafe_release(fdio_t* io);
+
+// This given a fdio_t, and a bitmask of posix-style events
+// (EPOLLIN, EPOLLOUT, EPOLLERR), this returns a handle that
+// may be waited upon and a  bitmask of which signals to
+// wait on for the desired events.
+//
+// The handle belongs to the fdio_t, is not duplicated,
+// and may be closed() by the fdio library but MUST NOT
+// be closed by the caller.
+//
+// If waiting is not supported by this fdio_t, the returned
+// handle is ZX_HANDLE_INVALID.
+//
+// This function is only safe to call on a fdio_t you
+// hold a reference to.  It is not required that fdio_unsafe_wait_end() be
+// called after this.
+void fdio_unsafe_wait_begin(fdio_t* io, uint32_t events,
+                            zx_handle_t* handle_out, zx_signals_t* signals_out);
+
+// This given a set of signals observed on a handle obtained
+// from fdio_unsafe_wait_begin() returns a set of posix-style events
+// that are indicated.
+//
+// This function is only safe to call on a fdio_t you
+// hold a reference to.
+void fdio_unsafe_wait_end(fdio_t* io, zx_signals_t signals, uint32_t* events_out);
+
+__END_CDECLS;
diff --git a/pkg/fdio/include/lib/fdio/util.h b/pkg/fdio/include/lib/fdio/util.h
new file mode 100644
index 0000000..fd30748
--- /dev/null
+++ b/pkg/fdio/include/lib/fdio/util.h
@@ -0,0 +1,115 @@
+// Copyright 2016 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#pragma once
+
+#include <zircon/types.h>
+#include <zircon/compiler.h>
+#include <stdint.h>
+#include <unistd.h>
+
+__BEGIN_CDECLS
+
+// These routines are "internal" to fdio but used by some companion
+// code like userboot and devmgr
+
+typedef struct fdio fdio_t;
+
+// Utilities to help assemble handles for a new process
+// may return up to FDIO_MAX_HANDLES
+zx_status_t fdio_clone_cwd(zx_handle_t* handles, uint32_t* types);
+zx_status_t fdio_clone_fd(int fd, int newfd, zx_handle_t* handles, uint32_t* types);
+zx_status_t fdio_transfer_fd(int fd, int newfd, zx_handle_t* handles, uint32_t* types);
+
+// Attempt to create an fdio fd from some handles and their associated types,
+// as returned from fdio_transfer_fd.
+//
+// Can only create fds around:
+// - Remote IO objects
+// - Pipes
+// - Connected sockets
+//
+// This function transfers ownership of handles to the fd on success, and
+// closes them on failure.
+zx_status_t fdio_create_fd(zx_handle_t* handles, uint32_t* types, size_t hcount, int* fd_out);
+
+// attempt to install a fdio in the unistd fd table
+// if fd >= 0, request a specific fd, and starting_fd is ignored
+// if fd < 0, request the first available fd >= starting_fd
+// returns fd on success
+// the fdio must have been upref'd on behalf of the fdtab first
+int fdio_bind_to_fd(fdio_t* io, int fd, int starting_fd);
+
+// attempt to detach an fdio_t from the fd table
+// returns ZX_ERR_INVALID_ARGS if fd is out of range or doesn't exist
+// returns ZX_ERR_UNAVAILABLE if the fd is busy or has been dup'd
+// returns fdio_t via io_out with refcount 1 on success
+zx_status_t fdio_unbind_from_fd(int fd, fdio_t** io_out);
+
+// If this fd represents a "service" (an rpc channel speaking
+// an unknown fidl protocol or a fuchsia.io.* protocol),
+// this call will return ZX_OK and return the underlying handle.
+// On both success and failure, the fd is effectively closed.
+//
+// ZX_ERR_NOT_SUPPORTED is returned if this fd does not represent
+// a FIDL transport
+//
+// ZX_ERR_UNAVAILABLE is returned if this fd has been dup()'d and
+// duplicates are sharing the FIDL transport
+zx_status_t fdio_get_service_handle(int fd, zx_handle_t* out);
+
+// creates a do-nothing fdio_t
+fdio_t* fdio_null_create(void);
+
+// Wraps a channel with an fdio_t using remote io.
+// Takes ownership of h and e.
+fdio_t* fdio_remote_create(zx_handle_t h, zx_handle_t event);
+
+// creates a fdio that wraps a log object
+// this will allocate a per-thread buffer (on demand) to assemble
+// entire log-lines and flush them on newline or buffer full.
+fdio_t* fdio_logger_create(zx_handle_t);
+
+typedef struct zxio_storage zxio_storage_t;
+
+// Creates an |fdio_t| that is backed by a |zxio_t|.
+//
+// The |zxio_t| is initialized with a null ops table. The |zxio_storage_t| for
+// the |zxio_t| is returned via |out_storage|. The client can re-initialize the
+// |zxio_storage_t| to customize the behavior of the |zxio_t|.
+//
+// To bind the |fdio_t| to a file descriptor, use |fdio_bind_to_fd|.
+//
+// Upon failure, returns NULL.
+fdio_t* fdio_zxio_create(zxio_storage_t** out_storage);
+
+// Attempt to connect a channel to a named service.
+// On success the channel is connected.  On failure
+// an error is returned and the handle is closed.
+zx_status_t fdio_service_connect(const char* svcpath, zx_handle_t h);
+
+// Attempt to connect a channel to a named service relative to dir.
+// On success the channel is connected.  On failure
+// an error is returned and the handle is closed.
+zx_status_t fdio_service_connect_at(zx_handle_t dir, const char* path, zx_handle_t h);
+
+// Same as |fdio_service_connect|, but allows the passing of flags.
+zx_status_t fdio_open(const char* path, uint32_t zxflags, zx_handle_t h);
+
+// Same as |fdio_service_connect_at, but allows the passing of flags.
+zx_status_t fdio_open_at(zx_handle_t dir, const char* path, uint32_t zxflags, zx_handle_t h);
+
+// Attempt to clone a service handle by doing a pipelined
+// CLONE operation, returning the new channel endpoint,
+// or ZX_HANDLE_INVALID.
+zx_handle_t fdio_service_clone(zx_handle_t h);
+
+// Attempt to clone a service handle by doing a pipelined
+// CLONE operation, using the provided serving channel.
+// On success srv is bound to a clone of h.  On failure
+// an error is returned and srv is closed.
+// Takes ownership of srv.
+zx_status_t fdio_service_clone_to(zx_handle_t h, zx_handle_t srv);
+
+__END_CDECLS
diff --git a/pkg/fdio/include/lib/fdio/vfs.h b/pkg/fdio/include/lib/fdio/vfs.h
new file mode 100644
index 0000000..f32ccb1
--- /dev/null
+++ b/pkg/fdio/include/lib/fdio/vfs.h
@@ -0,0 +1,82 @@
+// Copyright 2016 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#pragma once
+
+#include <zircon/types.h>
+#include <zircon/listnode.h>
+#include <zircon/compiler.h>
+
+#include <stdio.h>
+#include <unistd.h>  // ssize_t
+
+__BEGIN_CDECLS
+
+// On Fuchsia, the Block Device is transmitted by file descriptor, rather than
+// by path. This can prevent some racy behavior relating to FS start-up.
+#ifdef __Fuchsia__
+#define FS_FD_BLOCKDEVICE 200
+#endif
+
+// POSIX defines st_blocks to be the number of 512 byte blocks allocated
+// to the file. The "blkcnt" field of vnattr attempts to accomplish
+// this same goal, but by indirecting through VNATTR_BLKSIZE, we
+// reserve the right to change this "block size unit" (which is distinct from
+// "blksize", because POSIX) whenever we want.
+#define VNATTR_BLKSIZE 512
+
+typedef struct vnattr {
+    uint32_t valid;        // mask of which bits to set for setattr
+    uint32_t mode;
+    uint64_t inode;
+    uint64_t size;
+    uint64_t blksize;      // Block size for filesystem I/O
+    uint64_t blkcount;     // Number of VNATTR_BLKSIZE byte blocks allocated
+    uint64_t nlink;
+    uint64_t create_time;  // posix time (seconds since epoch)
+    uint64_t modify_time;  // posix time
+} vnattr_t;
+
+// mask that identifies what fields to set in setattr
+#define ATTR_CTIME  0000001
+#define ATTR_MTIME  0000002
+#define ATTR_ATIME  0000004  // not yet implemented
+
+// bits compatible with POSIX stat
+#define V_TYPE_MASK 0170000
+#define V_TYPE_SOCK 0140000
+#define V_TYPE_LINK 0120000
+#define V_TYPE_FILE 0100000
+#define V_TYPE_BDEV 0060000
+#define V_TYPE_DIR  0040000
+#define V_TYPE_CDEV 0020000
+#define V_TYPE_PIPE 0010000
+
+#define V_ISUID 0004000
+#define V_ISGID 0002000
+#define V_ISVTX 0001000
+#define V_IRWXU 0000700
+#define V_IRUSR 0000400
+#define V_IWUSR 0000200
+#define V_IXUSR 0000100
+#define V_IRWXG 0000070
+#define V_IRGRP 0000040
+#define V_IWGRP 0000020
+#define V_IXGRP 0000010
+#define V_IRWXO 0000007
+#define V_IROTH 0000004
+#define V_IWOTH 0000002
+#define V_IXOTH 0000001
+
+#define VTYPE_TO_DTYPE(mode) (((mode)&V_TYPE_MASK) >> 12)
+#define DTYPE_TO_VTYPE(type) (((type)&15) << 12)
+
+typedef struct vdirent {
+    uint64_t ino;
+    uint8_t size;
+    uint8_t type;
+    char name[0];
+} __PACKED vdirent_t;
+
+__END_CDECLS
diff --git a/pkg/fdio/include/lib/fdio/watcher.h b/pkg/fdio/include/lib/fdio/watcher.h
new file mode 100644
index 0000000..441edcf
--- /dev/null
+++ b/pkg/fdio/include/lib/fdio/watcher.h
@@ -0,0 +1,43 @@
+// Copyright 2016 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#pragma once
+
+#include <zircon/compiler.h>
+#include <lib/fdio/io.h>
+
+__BEGIN_CDECLS
+
+typedef zx_status_t (*watchdir_func_t)(int dirfd, int event, const char* fn, void* cookie);
+
+// This event occurs when a file is added or removed, including
+// (for fdio_watch_directory()) files that already exist.
+#define WATCH_EVENT_ADD_FILE 1
+#define WATCH_EVENT_REMOVE_FILE 2
+
+// This event occurs, once, when fdio_watch_directory() runs
+// out of existing files and has to start waiting for new
+// files to be added.
+#define WATCH_EVENT_IDLE 3
+
+// Call the provided callback (cb) for each file in directory
+// and each time a new file is added to the directory.
+//
+// If the callback returns a status other than ZX_OK, watching
+// stops and the callback's status is returned to the caller
+// of fdio_watch_directory.
+//
+// If the deadline expires, ZX_ERR_TIMED_OUT is returned to the
+// caller.  A deadline of ZX_TIME_INFINITE will never expire.
+//
+// The callback may use ZX_ERR_STOP as a way to signal to the
+// caller that it wants to stop because it found what it was
+// looking for, etc -- since this error code is not returned
+// by syscalls or public APIs, the callback does not need to
+// worry about it turning up normally.
+
+zx_status_t fdio_watch_directory(int dirfd, watchdir_func_t cb, zx_time_t deadline, void* cookie);
+
+
+__END_CDECLS
diff --git a/pkg/fdio/meta.json b/pkg/fdio/meta.json
new file mode 100644
index 0000000..51babcb
--- /dev/null
+++ b/pkg/fdio/meta.json
@@ -0,0 +1,32 @@
+{
+  "binaries": {
+    "arm64": {
+      "debug": ".build-id/eb/9ed8b78bc5865718b59bd2a3a47e3e28650f8f.debug", 
+      "dist": "arch/arm64/dist/libfdio.so", 
+      "link": "arch/arm64/lib/libfdio.so"
+    }, 
+    "x64": {
+      "debug": ".build-id/fb/6715ba574ce88bcfca5045ee90fef94163808f.debug", 
+      "dist": "arch/x64/dist/libfdio.so", 
+      "link": "arch/x64/lib/libfdio.so"
+    }
+  }, 
+  "deps": [], 
+  "format": "shared", 
+  "headers": [
+    "pkg/fdio/include/lib/fdio/debug.h", 
+    "pkg/fdio/include/lib/fdio/io.h", 
+    "pkg/fdio/include/lib/fdio/limits.h", 
+    "pkg/fdio/include/lib/fdio/namespace.h", 
+    "pkg/fdio/include/lib/fdio/private.h", 
+    "pkg/fdio/include/lib/fdio/spawn.h", 
+    "pkg/fdio/include/lib/fdio/unsafe.h", 
+    "pkg/fdio/include/lib/fdio/util.h", 
+    "pkg/fdio/include/lib/fdio/vfs.h", 
+    "pkg/fdio/include/lib/fdio/watcher.h"
+  ], 
+  "include_dir": "pkg/fdio/include", 
+  "name": "fdio", 
+  "root": "pkg/fdio", 
+  "type": "cc_prebuilt_library"
+}
\ No newline at end of file
diff --git a/pkg/fidl-async/bind.c b/pkg/fidl-async/bind.c
new file mode 100644
index 0000000..fad7132
--- /dev/null
+++ b/pkg/fidl-async/bind.c
@@ -0,0 +1,147 @@
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <lib/async/wait.h>
+#include <lib/fidl-async/bind.h>
+#include <stdlib.h>
+#include <string.h>
+#include <zircon/syscalls.h>
+
+typedef struct fidl_binding {
+    async_wait_t wait;
+    fidl_dispatch_t* dispatch;
+    async_dispatcher_t* dispatcher;
+    void* ctx;
+    const void* ops;
+} fidl_binding_t;
+
+typedef struct fidl_connection {
+    fidl_txn_t txn;
+    zx_handle_t channel;
+    zx_txid_t txid;
+    fidl_binding_t* binding;
+} fidl_connection_t;
+
+static zx_status_t fidl_reply(fidl_txn_t* txn, const fidl_msg_t* msg) {
+    fidl_connection_t* conn = (fidl_connection_t*)txn;
+    if (conn->txid == 0u)
+        return ZX_ERR_BAD_STATE;
+    if (msg->num_bytes < sizeof(fidl_message_header_t))
+        return ZX_ERR_INVALID_ARGS;
+    fidl_message_header_t* hdr = (fidl_message_header_t*)msg->bytes;
+    hdr->txid = conn->txid;
+    conn->txid = 0u;
+    return zx_channel_write(conn->channel, 0, msg->bytes, msg->num_bytes,
+                            msg->handles, msg->num_handles);
+}
+
+static void fidl_binding_destroy(fidl_binding_t* binding) {
+    zx_handle_close(binding->wait.object);
+    free(binding);
+}
+
+static void fidl_message_handler(async_dispatcher_t* dispatcher,
+                                 async_wait_t* wait,
+                                 zx_status_t status,
+                                 const zx_packet_signal_t* signal) {
+    fidl_binding_t* binding = (fidl_binding_t*)wait;
+    if (status != ZX_OK) {
+        goto shutdown;
+    }
+
+    if (signal->observed & ZX_CHANNEL_READABLE) {
+        char bytes[ZX_CHANNEL_MAX_MSG_BYTES];
+        zx_handle_t handles[ZX_CHANNEL_MAX_MSG_HANDLES];
+        for (uint64_t i = 0; i < signal->count; i++) {
+            fidl_msg_t msg = {
+                .bytes = bytes,
+                .handles = handles,
+                .num_bytes = 0u,
+                .num_handles = 0u,
+            };
+            status = zx_channel_read(wait->object, 0, bytes, handles,
+                                     ZX_CHANNEL_MAX_MSG_BYTES,
+                                     ZX_CHANNEL_MAX_MSG_HANDLES,
+                                     &msg.num_bytes, &msg.num_handles);
+            if (status == ZX_ERR_SHOULD_WAIT) {
+                break;
+            }
+            if (status != ZX_OK || msg.num_bytes < sizeof(fidl_message_header_t)) {
+                goto shutdown;
+            }
+            fidl_message_header_t* hdr = (fidl_message_header_t*)msg.bytes;
+            fidl_connection_t conn = {
+                .txn.reply = fidl_reply,
+                .channel = wait->object,
+                .txid = hdr->txid,
+                .binding = binding,
+            };
+            status = binding->dispatch(binding->ctx, &conn.txn, &msg, binding->ops);
+            switch (status) {
+            case ZX_OK:
+                status = async_begin_wait(dispatcher, wait);
+                if (status != ZX_OK) {
+                    goto shutdown;
+                }
+                return;
+            case ZX_ERR_ASYNC:
+                return;
+            default:
+                goto shutdown;
+            }
+        }
+    }
+
+shutdown:
+    fidl_binding_destroy(binding);
+}
+
+zx_status_t fidl_bind(async_dispatcher_t* dispatcher, zx_handle_t channel,
+                      fidl_dispatch_t* dispatch, void* ctx, const void* ops) {
+    fidl_binding_t* binding = calloc(1, sizeof(fidl_binding_t));
+    binding->wait.handler = fidl_message_handler;
+    binding->wait.object = channel;
+    binding->wait.trigger = ZX_CHANNEL_READABLE | ZX_CHANNEL_PEER_CLOSED;
+    binding->dispatch = dispatch;
+    binding->dispatcher = dispatcher;
+    binding->ctx = ctx;
+    binding->ops = ops;
+    zx_status_t status = async_begin_wait(dispatcher, &binding->wait);
+    if (status != ZX_OK) {
+        fidl_binding_destroy(binding);
+    }
+    return status;
+}
+
+typedef struct fidl_async_txn {
+    fidl_connection_t connection;
+} fidl_async_txn_t;
+
+fidl_async_txn_t* fidl_async_txn_create(fidl_txn_t* txn) {
+    fidl_connection_t* connection = (fidl_connection_t*) txn;
+
+    fidl_async_txn_t* async_txn = calloc(1, sizeof(fidl_async_txn_t));
+    memcpy(&async_txn->connection, connection, sizeof(*connection));
+
+    return async_txn;
+}
+
+fidl_txn_t* fidl_async_txn_borrow(fidl_async_txn_t* async_txn) {
+    return &async_txn->connection.txn;
+}
+
+zx_status_t fidl_async_txn_complete(fidl_async_txn_t* async_txn, bool rebind) {
+    zx_status_t status = ZX_OK;
+    if (rebind) {
+        status = async_begin_wait(async_txn->connection.binding->dispatcher,
+                                  &async_txn->connection.binding->wait);
+        if (status == ZX_OK) {
+            return ZX_OK;
+        }
+    }
+
+    fidl_binding_destroy(async_txn->connection.binding);
+    free(async_txn);
+    return status;
+}
diff --git a/pkg/fidl-async/include/lib/fidl-async/bind.h b/pkg/fidl-async/include/lib/fidl-async/bind.h
new file mode 100644
index 0000000..5fc6f8b
--- /dev/null
+++ b/pkg/fidl-async/include/lib/fidl-async/bind.h
@@ -0,0 +1,92 @@
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef LIB_FIDL_BIND_H_
+#define LIB_FIDL_BIND_H_
+
+#include <lib/async/dispatcher.h>
+#include <zircon/fidl.h>
+
+__BEGIN_CDECLS
+
+// A generic FIDL dispatch function.
+//
+// For FIDL interfaces with [Layout="Simple"], the C backend generates a
+// dispatch function that decodes the |msg| and calls through an |ops| table.
+//
+// This function signature matches the structure of these generated functions
+// but with the type of the |ops| table erased.
+//
+// Example:
+//
+//  fidl_bind(dispacher, channel, (fidl_dispatch_t*)spaceship_SpaceShip_dispatch, ctx, &kOps);
+//
+typedef zx_status_t(fidl_dispatch_t)(void* ctx, fidl_txn_t* txn,
+                                     fidl_msg_t* msg, const void* ops);
+
+// Binds a |dispatch| function to channel| using |dispatcher|.
+//
+// This function adds an |async_wait_t| to the given |dispatcher| that waits
+// asynchronously for new messages to arrive on |channel|. When a message
+// arrives, the |dispatch| function is called on one of the threads associated
+// with the |dispatcher| with the |fidl_msg_t| as well as the given |ctx| and
+// |ops|.
+//
+// Typically, the |dispatch| function is generated by the C backend for FIDL
+// interfaces with with [Layout="Simple"] (see |fidl_dispatch_t|). These
+// dispatch functions decode the |fidl_msg_t| and call through the |ops| table
+// implementations of the interface's methods, passing along the |ctx| and a
+// |fidl_txn_t| (if the method has a reply message).
+//
+// The |fidl_txn_t| passed to |dispatch| is valid only until |dispatch| returns.
+// If the method has a reply message, the |reply| function on the |fidl_txn_t|
+// object must be called synchronously within the |dispatch| call.
+//
+// If a client wishes to reply to the message asynchronously, |fidl_async_txn_create|
+// must be invoked on |fidl_txn_t|, and ZX_ERR_ASYNC must be returned.
+//
+// Returns whether |fidl_bind| was able to begin waiting on the given |channel|.
+// Upon any error, |channel| is closed and the binding is terminated. Shutting down
+// the |dispatcher| also results in |channel| being closed.
+//
+// It is safe to shutdown the dispatcher at any time.
+//
+// It is unsafe to destroy the dispatcher from within a dispatch function.
+// It is unsafe to destroy the dispatcher while any |fidl_async_txn_t| objects
+// are alive.
+zx_status_t fidl_bind(async_dispatcher_t* dispatcher, zx_handle_t channel,
+                      fidl_dispatch_t* dispatch, void* ctx, const void* ops);
+
+// An asynchronous FIDL txn.
+//
+// This is an opaque wrapper around |fidl_txn_t| which can extend the lifetime
+// of the object beyond the dispatched function.
+typedef struct fidl_async_txn fidl_async_txn_t;
+
+// Takes ownership of |txn| and allows usage of the txn beyond the currently
+// dispatched function.
+//
+// If this function is invoked within a dispatched function, that function
+// must return ZX_ERR_ASYNC.
+//
+// The result must be destroyed with a call to |fidl_async_txn_complete|.
+fidl_async_txn_t* fidl_async_txn_create(fidl_txn_t* txn);
+
+// Acquire a reference to the |fidl_txn_t| backing this txn object.
+//
+// It is unsafe to use this |fidl_txn_t| after |async_txn| is completed.
+fidl_txn_t* fidl_async_txn_borrow(fidl_async_txn_t* async_txn);
+
+// Destroys an asynchronous transaction created with |fidl_async_txn_create|.
+//
+// If requested, rebinds the underlying txn against the binding.
+// Returns an error if |rebind| is true and the transaction could not be
+// re-bound.
+//
+// In all cases, the |async_txn| object is consumed.
+zx_status_t fidl_async_txn_complete(fidl_async_txn_t* async_txn, bool rebind);
+
+__END_CDECLS
+
+#endif // LIB_FIDL_BIND_H_
diff --git a/pkg/fidl-async/meta.json b/pkg/fidl-async/meta.json
new file mode 100644
index 0000000..f5dfdbb
--- /dev/null
+++ b/pkg/fidl-async/meta.json
@@ -0,0 +1,22 @@
+{
+  "banjo_deps": [], 
+  "deps": [
+    "async", 
+    "fidl"
+  ], 
+  "fidl_deps": [], 
+  "files": [
+    "pkg/fidl-async/bind.c", 
+    "pkg/fidl-async/include/lib/fidl-async/bind.h"
+  ], 
+  "headers": [
+    "pkg/fidl-async/include/lib/fidl-async/bind.h"
+  ], 
+  "include_dir": "pkg/fidl-async/include", 
+  "name": "fidl-async", 
+  "root": "pkg/fidl-async", 
+  "sources": [
+    "pkg/fidl-async/bind.c"
+  ], 
+  "type": "cc_source_library"
+}
\ No newline at end of file
diff --git a/pkg/fidl/buffer_walker.h b/pkg/fidl/buffer_walker.h
new file mode 100644
index 0000000..92cb2e1
--- /dev/null
+++ b/pkg/fidl/buffer_walker.h
@@ -0,0 +1,809 @@
+// Copyright 2017 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#pragma once
+
+namespace fidl {
+namespace internal {
+
+// Some assumptions about data type layout.
+static_assert(offsetof(fidl_string_t, size) == 0u, "");
+static_assert(offsetof(fidl_string_t, data) == 8u, "");
+
+static_assert(offsetof(fidl_vector_t, count) == 0u, "");
+static_assert(offsetof(fidl_vector_t, data) == 8u, "");
+
+static_assert(ZX_HANDLE_INVALID == FIDL_HANDLE_ABSENT, "");
+
+template <bool kConst, class U>
+struct SetPtrConst;
+
+template <class U>
+struct SetPtrConst<false, U> {
+    typedef U* type;
+};
+
+template <class U>
+struct SetPtrConst<true, U> {
+    typedef const U* type;
+};
+
+// Walks over a FIDL buffer and validates/encodes/decodes it per-Derived.
+//
+// kMutating controls whether this deals with mutable bytes or immutable bytes
+// (validation wants immutable, encode/decode wants mutable)
+//
+// kContinueAfterErrors controls whether parsing is continued upon failure (encode needs this to
+// see all available handles).
+//
+// Derived should offer the following methods:
+//
+//   const? uint8_t* bytes() - returns the start of the buffer of bytes
+//   uint32_t num_bytes() - returns the number of bytes in said buffer
+//   uint32_t num_handles() - returns the number of handles that are claimable
+//   bool ValidateOutOfLineStorageClaim(const void* a, const void* b)
+//      - returns true if a legally points to b
+//   void UnclaimedHandle(zx_handle_t*) - notes that a handle was skipped
+//   void ClaimedHandle(zx_handle_t*, uint32_t idx) - notes that a handle was claimed
+//   PointerState GetPointerState(const void* ptr) - returns whether a pointer is present or not
+//   HandleState GetHandleState(zx_handle_t) - returns if a handle is present or not
+//   void UpdatePointer(T**p, T*v) - mutates a pointer representation for a present pointer
+//   void SetError(const char* error_msg) - flags that an error occurred
+template <class Derived, bool kMutating, bool kContinueAfterErrors>
+class BufferWalker {
+public:
+    explicit BufferWalker(const fidl_type* type)
+        : type_(type) {}
+
+    void Walk() {
+        // The first decode is special. It must be a struct or a table.
+        // We need to know the size of the first element to compute the start of
+        // the out-of-line allocations.
+
+        if (type_ == nullptr) {
+            SetError("Cannot decode a null fidl type");
+            return;
+        }
+
+        if (bytes() == nullptr) {
+            SetError("Cannot decode null bytes");
+            return;
+        }
+
+        switch (type_->type_tag) {
+        case fidl::kFidlTypeStruct:
+            if (num_bytes() < type_->coded_struct.size) {
+                SetError("Message size is smaller than expected");
+                return;
+            }
+            out_of_line_offset_ = static_cast<uint32_t>(fidl::FidlAlign(type_->coded_struct.size));
+            break;
+        case fidl::kFidlTypeTable:
+            if (num_bytes() < sizeof(fidl_vector_t)) {
+                SetError("Message size is smaller than expected");
+                return;
+            }
+            out_of_line_offset_ = static_cast<uint32_t>(fidl::FidlAlign(sizeof(fidl_vector_t)));
+            break;
+        default:
+            SetError("Message must be a struct or a table");
+            return;
+        }
+
+        Push(Frame::DoneSentinel());
+        Push(Frame(type_, 0u));
+
+// Macro to insert the relevant goop required to support two control flows here:
+// one where we keep reading after error, and another where we return immediately.
+// No runtime overhead thanks to if constexpr magic.
+#define FIDL_POP_AND_CONTINUE_OR_RETURN \
+    if (kContinueAfterErrors) {         \
+        Pop();                          \
+        continue;                       \
+    } else {                            \
+        return;                         \
+    }
+
+        for (;;) {
+            Frame* frame = Peek();
+
+            switch (frame->state) {
+            case Frame::kStateStruct: {
+                const uint32_t field_index = frame->NextStructField();
+                if (field_index == frame->struct_state.field_count) {
+                    Pop();
+                    continue;
+                }
+                const fidl::FidlField& field = frame->struct_state.fields[field_index];
+                const fidl_type_t* field_type = field.type;
+                const uint32_t field_offset = frame->offset + field.offset;
+                if (!Push(Frame(field_type, field_offset))) {
+                    SetError("recursion depth exceeded processing struct");
+                    FIDL_POP_AND_CONTINUE_OR_RETURN;
+                }
+                continue;
+            }
+            case Frame::kStateStructPointer: {
+                switch (GetPointerState(TypedAt<void>(frame->offset))) {
+                case PointerState::PRESENT:
+                    break;
+                case PointerState::ABSENT:
+                    Pop();
+                    continue;
+                default:
+                    SetError("Tried to decode a bad struct pointer");
+                    FIDL_POP_AND_CONTINUE_OR_RETURN;
+                }
+                auto struct_ptr_ptr = TypedAt<void*>(frame->offset);
+                if (!ClaimOutOfLineStorage(frame->struct_pointer_state.struct_type->size,
+                                           *struct_ptr_ptr, &frame->offset)) {
+                    SetError("message wanted to store too large of a nullable struct");
+                    FIDL_POP_AND_CONTINUE_OR_RETURN;
+                }
+                UpdatePointer(struct_ptr_ptr, TypedAt<void>(frame->offset));
+                const fidl::FidlCodedStruct* coded_struct = frame->struct_pointer_state.struct_type;
+                *frame = Frame(coded_struct, frame->offset);
+                continue;
+            }
+            case Frame::kStateTable: {
+                if (frame->field == 0u) {
+                    auto envelope_vector_ptr = TypedAt<fidl_vector_t>(frame->offset);
+                    switch (GetPointerState(&envelope_vector_ptr->data)) {
+                    case PointerState::PRESENT:
+                        break;
+                    case PointerState::ABSENT:
+                        SetError("Table data cannot be absent");
+                        FIDL_POP_AND_CONTINUE_OR_RETURN;
+                    default:
+                        SetError("message tried to decode a non-present vector");
+                        FIDL_POP_AND_CONTINUE_OR_RETURN;
+                    }
+                    uint32_t size;
+                    if (mul_overflow(envelope_vector_ptr->count, 2 * sizeof(uint64_t), &size)) {
+                        SetError("integer overflow calculating table size");
+                        FIDL_POP_AND_CONTINUE_OR_RETURN;
+                    }
+                    if (!ClaimOutOfLineStorage(size, envelope_vector_ptr->data, &frame->offset)) {
+                        SetError("message wanted to store too large of a table");
+                        FIDL_POP_AND_CONTINUE_OR_RETURN;
+                    }
+                    UpdatePointer(&envelope_vector_ptr->data, TypedAt<void>(frame->offset));
+                    frame->field = 1;
+                    frame->table_state.known_index = 0;
+                    frame->table_state.present_count = static_cast<uint32_t>(envelope_vector_ptr->count);
+                    frame->table_state.end_offset = out_of_line_offset_;
+                    frame->table_state.end_handle = handle_idx_;
+                    continue;
+                }
+                if (frame->table_state.end_offset != out_of_line_offset_) {
+                    SetError("Table field was mis-sized");
+                    FIDL_POP_AND_CONTINUE_OR_RETURN;
+                }
+                if (frame->table_state.end_handle != handle_idx_) {
+                    SetError("Table handles were mis-sized");
+                    FIDL_POP_AND_CONTINUE_OR_RETURN;
+                }
+                if (frame->field > frame->table_state.present_count) {
+                    Pop();
+                    continue;
+                }
+                const fidl::FidlTableField* known_field = nullptr;
+                if (frame->table_state.known_index < frame->table_state.field_count) {
+                    const fidl::FidlTableField* field =
+                        &frame->table_state.fields[frame->table_state.known_index];
+                    if (field->ordinal == frame->field) {
+                        known_field = field;
+                        frame->table_state.known_index++;
+                    }
+                }
+                const uint32_t tag_offset = static_cast<uint32_t>(
+                    frame->offset + (frame->field - 1) * 2 * sizeof(uint64_t));
+                const uint32_t data_offset = static_cast<uint32_t>(
+                    tag_offset + sizeof(uint64_t));
+                const uint64_t packed_sizes = *TypedAt<uint64_t>(tag_offset);
+                frame->field++;
+                switch (GetPointerState(TypedAt<void>(data_offset))) {
+                case PointerState::PRESENT:
+                    if (packed_sizes != 0)
+                        break; // expected
+
+                    SetError("Table envelope has present data pointer, but no data, and no handles");
+                    FIDL_POP_AND_CONTINUE_OR_RETURN;
+                case PointerState::ABSENT:
+                    if (packed_sizes == 0)
+                        continue; // skip
+
+                    SetError("Table envelope has absent data pointer, yet has data and/or handles");
+                    FIDL_POP_AND_CONTINUE_OR_RETURN;
+                default:
+                    SetError("Table envelope has bad data pointer");
+                    FIDL_POP_AND_CONTINUE_OR_RETURN;
+                }
+                uint32_t offset;
+                uint32_t handles;
+                const uint32_t table_bytes = static_cast<uint32_t>(packed_sizes & 0xffffffffu);
+                const uint32_t table_handles = static_cast<uint32_t>(packed_sizes >> 32);
+                if (add_overflow(out_of_line_offset_, table_bytes, &offset) || offset > num_bytes()) {
+                    SetError("integer overflow decoding table field");
+                    FIDL_POP_AND_CONTINUE_OR_RETURN;
+                }
+                if (add_overflow(handle_idx_, table_handles, &handles) ||
+                    handles > num_handles()) {
+                    SetError("integer overflow decoding table handles");
+                    FIDL_POP_AND_CONTINUE_OR_RETURN;
+                }
+                frame->table_state.end_offset = offset;
+                frame->table_state.end_handle = handles;
+                if (known_field != nullptr) {
+                    const fidl_type_t* field_type = known_field->type;
+                    uint32_t field_offset;
+                    if (!ClaimOutOfLineStorage(TypeSize(field_type), TypedAt<void*>(data_offset), &field_offset)) {
+                        SetError("table wanted too many bytes in field");
+                        FIDL_POP_AND_CONTINUE_OR_RETURN;
+                    }
+                    UpdatePointer(TypedAt<void*>(data_offset), TypedAt<void>(field_offset));
+                    if (!Push(Frame(field_type, field_offset))) {
+                        SetError("recursion depth exceeded decoding table");
+                        FIDL_POP_AND_CONTINUE_OR_RETURN;
+                    }
+                } else {
+                    // Table data will not be processed: discard it.
+                    uint32_t field_offset;
+                    if (!ClaimOutOfLineStorage(table_bytes, TypedAt<void*>(data_offset), &field_offset)) {
+                        SetError("table wanted too many bytes in field");
+                        FIDL_POP_AND_CONTINUE_OR_RETURN;
+                    }
+                    UpdatePointer(TypedAt<void*>(data_offset), TypedAt<void>(field_offset));
+                    for (uint32_t i = 0; i < table_handles; i++) {
+                        if (!ClaimHandle(nullptr)) {
+                            SetError("expected handle not present");
+                            FIDL_POP_AND_CONTINUE_OR_RETURN;
+                        }
+                    }
+                }
+                continue;
+            }
+            case Frame::kStateTablePointer: {
+                switch (GetPointerState(TypedAt<void>(frame->offset))) {
+                case PointerState::PRESENT:
+                    break;
+                case PointerState::ABSENT:
+                    Pop();
+                    continue;
+                default:
+                    SetError("Tried to decode a bad table pointer");
+                    FIDL_POP_AND_CONTINUE_OR_RETURN;
+                }
+                auto table_ptr_ptr = TypedAt<void*>(frame->offset);
+                if (!ClaimOutOfLineStorage(sizeof(fidl_vector_t), *table_ptr_ptr, &frame->offset)) {
+                    SetError("message wanted to store too large of a nullable table");
+                    FIDL_POP_AND_CONTINUE_OR_RETURN;
+                }
+                UpdatePointer(table_ptr_ptr, TypedAt<void>(frame->offset));
+                const fidl::FidlCodedTable* coded_table = frame->table_pointer_state.table_type;
+                *frame = Frame(coded_table, frame->offset);
+                continue;
+            }
+            case Frame::kStateUnion: {
+                fidl_union_tag_t union_tag = *TypedAt<fidl_union_tag_t>(frame->offset);
+                if (union_tag >= frame->union_state.type_count) {
+                    SetError("Tried to decode a bad union discriminant");
+                    FIDL_POP_AND_CONTINUE_OR_RETURN;
+                }
+                const fidl_type_t* member = frame->union_state.types[union_tag];
+                if (!member) {
+                    Pop();
+                    continue;
+                }
+                frame->offset += frame->union_state.data_offset;
+                *frame = Frame(member, frame->offset);
+                continue;
+            }
+            case Frame::kStateUnionPointer: {
+                auto union_ptr_ptr = TypedAt<fidl_union_tag_t*>(frame->offset);
+                switch (GetPointerState(TypedAt<void>(frame->offset))) {
+                case PointerState::PRESENT:
+                    break;
+                case PointerState::ABSENT:
+                    Pop();
+                    continue;
+                default:
+                    SetError("Tried to decode a bad union pointer");
+                    FIDL_POP_AND_CONTINUE_OR_RETURN;
+                }
+                if (!ClaimOutOfLineStorage(frame->union_pointer_state.union_type->size, *union_ptr_ptr,
+                                           &frame->offset)) {
+                    SetError("message wanted to store too large of a nullable union");
+                    FIDL_POP_AND_CONTINUE_OR_RETURN;
+                }
+                UpdatePointer(union_ptr_ptr, TypedAt<fidl_union_tag_t>(frame->offset));
+                const fidl::FidlCodedUnion* coded_union = frame->union_pointer_state.union_type;
+                *frame = Frame(coded_union, frame->offset);
+                continue;
+            }
+            case Frame::kStateArray: {
+                const uint32_t element_offset = frame->NextArrayOffset();
+                if (element_offset == frame->array_state.array_size) {
+                    Pop();
+                    continue;
+                }
+                const fidl_type_t* element_type = frame->array_state.element;
+                const uint32_t offset = frame->offset + element_offset;
+                if (!Push(Frame(element_type, offset))) {
+                    SetError("recursion depth exceeded decoding array");
+                    FIDL_POP_AND_CONTINUE_OR_RETURN;
+                }
+                continue;
+            }
+            case Frame::kStateString: {
+                auto string_ptr = TypedAt<fidl_string_t>(frame->offset);
+                // The string storage may be Absent for nullable strings and must
+                // otherwise be Present. No other values are allowed.
+                switch (GetPointerState(&string_ptr->data)) {
+                case PointerState::PRESENT:
+                    break;
+                case PointerState::ABSENT:
+                    if (!frame->string_state.nullable) {
+                        SetError("message tried to decode an absent non-nullable string");
+                        FIDL_POP_AND_CONTINUE_OR_RETURN;
+                    }
+                    if (string_ptr->size != 0u) {
+                        SetError("message tried to decode an absent string of non-zero length");
+                        FIDL_POP_AND_CONTINUE_OR_RETURN;
+                    }
+                    Pop();
+                    continue;
+                default:
+                    SetError(
+                        "message tried to decode a string that is neither present nor absent");
+                    FIDL_POP_AND_CONTINUE_OR_RETURN;
+                }
+                uint64_t bound = frame->string_state.max_size;
+                uint64_t size = string_ptr->size;
+                if (size > bound) {
+                    SetError("message tried to decode too large of a bounded string");
+                    FIDL_POP_AND_CONTINUE_OR_RETURN;
+                }
+                uint32_t string_data_offset = 0u;
+                if (!ClaimOutOfLineStorage(static_cast<uint32_t>(size), string_ptr->data, &string_data_offset)) {
+                    SetError("decoding a string overflowed buffer");
+                    FIDL_POP_AND_CONTINUE_OR_RETURN;
+                }
+                UpdatePointer(&string_ptr->data, TypedAt<char>(string_data_offset));
+                Pop();
+                continue;
+            }
+            case Frame::kStateHandle: {
+                auto handle_ptr = TypedAt<zx_handle_t>(frame->offset);
+                // The handle storage may be Absent for nullable handles and must
+                // otherwise be Present. No other values are allowed.
+                switch (GetHandleState(*handle_ptr)) {
+                case HandleState::ABSENT:
+                    if (frame->handle_state.nullable) {
+                        Pop();
+                        continue;
+                    }
+                    SetError("message tried to decode a non-present handle");
+                    FIDL_POP_AND_CONTINUE_OR_RETURN;
+                case HandleState::PRESENT:
+                    if (!ClaimHandle(handle_ptr)) {
+                        SetError("message decoded too many handles");
+                        FIDL_POP_AND_CONTINUE_OR_RETURN;
+                    }
+                    Pop();
+                    continue;
+                default:
+                    // The value at the handle was garbage.
+                    SetError("message tried to decode a garbage handle");
+                    FIDL_POP_AND_CONTINUE_OR_RETURN;
+                }
+            }
+            case Frame::kStateVector: {
+                auto vector_ptr = TypedAt<fidl_vector_t>(frame->offset);
+                // The vector storage may be Absent for nullable vectors and must
+                // otherwise be Present. No other values are allowed.
+                switch (GetPointerState(&vector_ptr->data)) {
+                case PointerState::PRESENT:
+                    break;
+                case PointerState::ABSENT:
+                    if (!frame->vector_state.nullable) {
+                        SetError("message tried to decode an absent non-nullable vector");
+                        FIDL_POP_AND_CONTINUE_OR_RETURN;
+                    }
+                    if (vector_ptr->count != 0u) {
+                        SetError("message tried to decode an absent vector of non-zero elements");
+                        FIDL_POP_AND_CONTINUE_OR_RETURN;
+                    }
+                    Pop();
+                    continue;
+                default:
+                    SetError("message tried to decode a non-present vector");
+                    FIDL_POP_AND_CONTINUE_OR_RETURN;
+                }
+                if (vector_ptr->count > frame->vector_state.max_count) {
+                    SetError("message tried to decode too large of a bounded vector");
+                    FIDL_POP_AND_CONTINUE_OR_RETURN;
+                }
+                uint32_t size;
+                if (mul_overflow(vector_ptr->count, frame->vector_state.element_size, &size)) {
+                    SetError("integer overflow calculating vector size");
+                    FIDL_POP_AND_CONTINUE_OR_RETURN;
+                }
+                if (!ClaimOutOfLineStorage(size, vector_ptr->data, &frame->offset)) {
+                    SetError("message wanted to store too large of a vector");
+                    FIDL_POP_AND_CONTINUE_OR_RETURN;
+                }
+                UpdatePointer(&vector_ptr->data, TypedAt<void>(frame->offset));
+                if (frame->vector_state.element) {
+                    // Continue by decoding the vector elements as an array.
+                    *frame = Frame(frame->vector_state.element, size,
+                                   frame->vector_state.element_size, frame->offset);
+                } else {
+                    // If there is no element type pointer, there is
+                    // nothing to decode in the vector secondary
+                    // payload. So just continue.
+                    Pop();
+                }
+                continue;
+            }
+            case Frame::kStateDone: {
+                if (out_of_line_offset_ != num_bytes()) {
+                    SetError("message did not decode all provided bytes");
+                }
+                return;
+            }
+            }
+        }
+
+#undef FIDL_POP_AND_CONTINUE_OR_RETURN
+    }
+
+protected:
+    void SetError(const char* error_msg) {
+        derived()->SetError(error_msg);
+    }
+
+    template <typename T>
+    typename SetPtrConst<!kMutating, T>::type TypedAt(uint32_t offset) const {
+        return reinterpret_cast<typename SetPtrConst<!kMutating, T>::type>(bytes() + offset);
+    }
+
+    enum class PointerState : uintptr_t {
+        PRESENT = FIDL_ALLOC_PRESENT,
+        ABSENT = FIDL_ALLOC_ABSENT,
+        INVALID = 1 // *OR* *ANY* non PRESENT/ABSENT value.
+    };
+
+    enum class HandleState : zx_handle_t {
+        PRESENT = FIDL_HANDLE_PRESENT,
+        ABSENT = FIDL_HANDLE_ABSENT,
+        INVALID = 1 // *OR* *ANY* non PRESENT/ABSENT value.
+    };
+
+    uint32_t handle_idx() const { return handle_idx_; }
+
+private:
+    Derived* derived() {
+        return static_cast<Derived*>(this);
+    }
+
+    const Derived* derived() const {
+        return static_cast<const Derived*>(this);
+    }
+
+    // Returns a pointer to the bytes in the message.
+    auto bytes() const {
+        return derived()->bytes();
+    }
+
+    // Returns the number of bytes in the message.
+    auto num_bytes() const {
+        return derived()->num_bytes();
+    }
+
+    // Returns the number of handles in the message (encoding: the max number of handles in the message).
+    auto num_handles() const {
+        return derived()->num_handles();
+    }
+
+    // Returns PRESENT/ABSENT/INVALID for a given pointer value.
+    PointerState GetPointerState(const void* ptr) const {
+        return derived()->GetPointerState(ptr);
+    }
+
+    // Returns PRESENT/ABSENT/INVALID for a given handle value.
+    HandleState GetHandleState(zx_handle_t p) const {
+        return derived()->GetHandleState(p);
+    }
+
+    // If required: mutate a pointer to the dual representation.
+    template <class T2, class T1>
+    void UpdatePointer(T2 p, T1 v) {
+        derived()->UpdatePointer(p, v);
+    }
+
+    // Returns true when a handle was claimed, and false when the
+    // handles are exhausted.
+    template <class ZxHandleTPointer>
+    bool ClaimHandle(ZxHandleTPointer out_handle) {
+        if (handle_idx_ == num_handles()) {
+            derived()->UnclaimedHandle(out_handle);
+            return false;
+        }
+        derived()->ClaimedHandle(out_handle, handle_idx_);
+        ++handle_idx_;
+        return true;
+    }
+
+    // Returns true when the buffer space is claimed, and false when
+    // the requested claim is too large for bytes_.
+    bool ClaimOutOfLineStorage(uint32_t size, const void* storage, uint32_t* out_offset) {
+        if (!derived()->ValidateOutOfLineStorageClaim(storage, &bytes()[out_of_line_offset_])) {
+            return false;
+        }
+
+        // We have to manually maintain alignment here. For example, a pointer
+        // to a struct that is 4 bytes still needs to advance the next
+        // out-of-line offset by 8 to maintain the aligned-to-FIDL_ALIGNMENT
+        // property.
+        static constexpr uint32_t mask = FIDL_ALIGNMENT - 1;
+        uint32_t offset = out_of_line_offset_;
+        if (add_overflow(offset, size, &offset) ||
+            add_overflow(offset, mask, &offset)) {
+            return false;
+        }
+        offset &= ~mask;
+
+        if (offset > num_bytes()) {
+            return false;
+        }
+        *out_offset = out_of_line_offset_;
+        out_of_line_offset_ = offset;
+        return true;
+    }
+
+    uint32_t TypeSize(const fidl_type_t* type) {
+        switch (type->type_tag) {
+        case fidl::kFidlTypeStructPointer:
+        case fidl::kFidlTypeTablePointer:
+        case fidl::kFidlTypeUnionPointer:
+            return sizeof(uint64_t);
+        case fidl::kFidlTypeHandle:
+            return sizeof(zx_handle_t);
+        case fidl::kFidlTypeStruct:
+            return type->coded_struct.size;
+        case fidl::kFidlTypeTable:
+            return sizeof(fidl_vector_t);
+        case fidl::kFidlTypeUnion:
+            return type->coded_union.size;
+        case fidl::kFidlTypeString:
+            return sizeof(fidl_string_t);
+        case fidl::kFidlTypeArray:
+            return type->coded_array.array_size;
+        case fidl::kFidlTypeVector:
+            return sizeof(fidl_vector_t);
+        }
+        abort();
+        return 0;
+    }
+
+    // Functions that manipulate the decoding stack frames.
+    struct Frame {
+        Frame(const fidl_type_t* fidl_type, uint32_t offset)
+            : offset(offset) {
+            switch (fidl_type->type_tag) {
+            case fidl::kFidlTypeStruct:
+                state = kStateStruct;
+                struct_state.fields = fidl_type->coded_struct.fields;
+                struct_state.field_count = fidl_type->coded_struct.field_count;
+                break;
+            case fidl::kFidlTypeStructPointer:
+                state = kStateStructPointer;
+                struct_pointer_state.struct_type = fidl_type->coded_struct_pointer.struct_type;
+                break;
+            case fidl::kFidlTypeTable:
+                state = kStateTable;
+                table_state.fields = fidl_type->coded_table.fields;
+                table_state.field_count = fidl_type->coded_table.field_count;
+                table_state.present_count = 0;
+                break;
+            case fidl::kFidlTypeTablePointer:
+                state = kStateTablePointer;
+                table_pointer_state.table_type = fidl_type->coded_table_pointer.table_type;
+                break;
+            case fidl::kFidlTypeUnion:
+                state = kStateUnion;
+                union_state.types = fidl_type->coded_union.types;
+                union_state.type_count = fidl_type->coded_union.type_count;
+                union_state.data_offset = fidl_type->coded_union.data_offset;
+                break;
+            case fidl::kFidlTypeUnionPointer:
+                state = kStateUnionPointer;
+                union_pointer_state.union_type = fidl_type->coded_union_pointer.union_type;
+                break;
+            case fidl::kFidlTypeArray:
+                state = kStateArray;
+                array_state.element = fidl_type->coded_array.element;
+                array_state.array_size = fidl_type->coded_array.array_size;
+                array_state.element_size = fidl_type->coded_array.element_size;
+                break;
+            case fidl::kFidlTypeString:
+                state = kStateString;
+                string_state.max_size = fidl_type->coded_string.max_size;
+                string_state.nullable = fidl_type->coded_string.nullable;
+                break;
+            case fidl::kFidlTypeHandle:
+                state = kStateHandle;
+                handle_state.nullable = fidl_type->coded_handle.nullable;
+                break;
+            case fidl::kFidlTypeVector:
+                state = kStateVector;
+                vector_state.element = fidl_type->coded_vector.element;
+                vector_state.max_count = fidl_type->coded_vector.max_count;
+                vector_state.element_size = fidl_type->coded_vector.element_size;
+                vector_state.nullable = fidl_type->coded_vector.nullable;
+                break;
+            }
+        }
+
+        Frame(const fidl::FidlCodedStruct* coded_struct, uint32_t offset)
+            : offset(offset) {
+            state = kStateStruct;
+            struct_state.fields = coded_struct->fields;
+            struct_state.field_count = coded_struct->field_count;
+        }
+
+        Frame(const fidl::FidlCodedTable* coded_table, uint32_t offset)
+            : offset(offset) {
+            state = kStateStruct;
+            table_state.fields = coded_table->fields;
+            table_state.field_count = coded_table->field_count;
+        }
+
+        Frame(const fidl::FidlCodedUnion* coded_union, uint32_t offset)
+            : offset(offset) {
+            state = kStateUnion;
+            union_state.types = coded_union->types;
+            union_state.type_count = coded_union->type_count;
+            union_state.data_offset = coded_union->data_offset;
+        }
+
+        Frame(const fidl_type_t* element, uint32_t array_size, uint32_t element_size,
+              uint32_t offset)
+            : offset(offset) {
+            state = kStateArray;
+            array_state.element = element;
+            array_state.array_size = array_size;
+            array_state.element_size = element_size;
+        }
+
+        // The default constructor does nothing when initializing the stack of frames.
+        Frame() {}
+
+        static Frame DoneSentinel() {
+            Frame frame;
+            frame.state = kStateDone;
+            return frame;
+        }
+
+        uint32_t NextStructField() {
+            ZX_DEBUG_ASSERT(state == kStateStruct);
+
+            uint32_t current = field;
+            field += 1;
+            return current;
+        }
+
+        uint32_t NextArrayOffset() {
+            ZX_DEBUG_ASSERT(state == kStateArray);
+
+            uint32_t current = field;
+            field += array_state.element_size;
+            return current;
+        }
+
+        enum : int {
+            kStateStruct,
+            kStateStructPointer,
+            kStateTable,
+            kStateTablePointer,
+            kStateUnion,
+            kStateUnionPointer,
+            kStateArray,
+            kStateString,
+            kStateHandle,
+            kStateVector,
+
+            kStateDone,
+        } state;
+        // A byte offset into bytes_;
+        uint32_t offset;
+
+        // This is a subset of the information recorded in the
+        // fidl_type structures needed for decoding state. For
+        // example, struct sizes do not need to be present here.
+        union {
+            struct {
+                const fidl::FidlField* fields;
+                uint32_t field_count;
+            } struct_state;
+            struct {
+                const fidl::FidlCodedStruct* struct_type;
+            } struct_pointer_state;
+            struct {
+                const fidl::FidlTableField* fields;
+                uint32_t known_index;
+                uint32_t field_count;
+                uint32_t present_count;
+                uint32_t end_offset;
+                uint32_t end_handle;
+            } table_state;
+            struct {
+                const fidl::FidlCodedTable* table_type;
+            } table_pointer_state;
+            struct {
+                const fidl_type_t* const* types;
+                uint32_t type_count;
+                uint32_t data_offset;
+            } union_state;
+            struct {
+                const fidl::FidlCodedUnion* union_type;
+            } union_pointer_state;
+            struct {
+                const fidl_type_t* element;
+                uint32_t array_size;
+                uint32_t element_size;
+            } array_state;
+            struct {
+                uint32_t max_size;
+                bool nullable;
+            } string_state;
+            struct {
+                bool nullable;
+            } handle_state;
+            struct {
+                const fidl_type* element;
+                uint32_t max_count;
+                uint32_t element_size;
+                bool nullable;
+            } vector_state;
+        };
+
+        uint32_t field = 0u;
+    };
+
+    // Returns true on success and false on recursion overflow.
+    bool Push(Frame frame) {
+        if (depth_ == FIDL_RECURSION_DEPTH) {
+            return false;
+        }
+        decoding_frames_[depth_] = frame;
+        ++depth_;
+        return true;
+    }
+
+    void Pop() {
+        ZX_DEBUG_ASSERT(depth_ != 0u);
+        --depth_;
+    }
+
+    Frame* Peek() {
+        ZX_DEBUG_ASSERT(depth_ != 0u);
+        return &decoding_frames_[depth_ - 1];
+    }
+
+    // Message state passed in to the constructor.
+    const fidl_type_t* const type_;
+
+    // Internal state.
+    uint32_t handle_idx_ = 0u;
+    uint32_t out_of_line_offset_ = 0u;
+
+    // Decoding stack state.
+    uint32_t depth_ = 0u;
+    Frame decoding_frames_[FIDL_RECURSION_DEPTH];
+};
+
+} // namespace internal
+} // namespace fidl
diff --git a/pkg/fidl/builder.cpp b/pkg/fidl/builder.cpp
new file mode 100644
index 0000000..476b7ee
--- /dev/null
+++ b/pkg/fidl/builder.cpp
@@ -0,0 +1,62 @@
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <lib/fidl/cpp/builder.h>
+
+#include <string.h>
+
+#include <lib/fidl/internal.h>
+
+namespace fidl {
+
+Builder::Builder()
+    : capacity_(0u), at_(0u), buffer_(nullptr) {}
+
+Builder::Builder(void* buffer, uint32_t capacity)
+    : capacity_(capacity), at_(0u), buffer_(static_cast<uint8_t*>(buffer)) {
+}
+
+Builder::~Builder() = default;
+
+Builder::Builder(Builder&& other)
+    : capacity_(other.capacity_),
+      at_(other.at_),
+      buffer_(other.buffer_) {
+    other.Reset(nullptr, 0);
+}
+
+Builder& Builder::operator=(Builder&& other) {
+    if (this != &other) {
+        capacity_ = other.capacity_;
+        at_ = other.at_;
+        buffer_ = other.buffer_;
+        other.Reset(nullptr, 0);
+    }
+    return *this;
+}
+
+void* Builder::Allocate(uint32_t size) {
+    uint64_t limit = FidlAlign(at_ + size);
+    if (limit > capacity_)
+        return nullptr;
+    uint8_t* result = &buffer_[at_];
+    memset(buffer_ + at_, 0, limit - at_);
+    at_ = static_cast<uint32_t>(limit);
+    return result;
+}
+
+BytePart Builder::Finalize() {
+    BytePart bytes(buffer_, capacity_, at_);
+    capacity_ = 0u;
+    at_ = 0u;
+    return bytes;
+}
+
+void Builder::Reset(void* buffer, uint32_t capacity) {
+    buffer_ = static_cast<uint8_t*>(buffer);
+    capacity_ = capacity;
+    at_ = 0u;
+}
+
+} // namespace fidl
diff --git a/pkg/fidl/decoding.cpp b/pkg/fidl/decoding.cpp
new file mode 100644
index 0000000..3066778
--- /dev/null
+++ b/pkg/fidl/decoding.cpp
@@ -0,0 +1,115 @@
+// Copyright 2017 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <lib/fidl/coding.h>
+
+#include <stdalign.h>
+#include <stdint.h>
+#include <stdlib.h>
+
+#include <lib/fidl/internal.h>
+#include <zircon/assert.h>
+#include <zircon/compiler.h>
+
+#ifdef __Fuchsia__
+#include <zircon/syscalls.h>
+#endif
+
+#include "buffer_walker.h"
+
+// TODO(kulakowski) Design zx_status_t error values.
+
+namespace {
+
+class FidlDecoder final : public fidl::internal::BufferWalker<FidlDecoder, true, false> {
+    typedef fidl::internal::BufferWalker<FidlDecoder, true, false> Super;
+
+public:
+    FidlDecoder(const fidl_type_t* type, void* bytes, uint32_t num_bytes,
+                const zx_handle_t* handles, uint32_t num_handles, const char** out_error_msg)
+        : Super(type), bytes_(static_cast<uint8_t*>(bytes)), num_bytes_(num_bytes),
+          handles_(handles), num_handles_(num_handles), out_error_msg_(out_error_msg) {}
+
+    void Walk() {
+        if (handles_ == nullptr && num_handles_ != 0u) {
+            SetError("Cannot provide non-zero handle count and null handle pointer");
+            return;
+        }
+        Super::Walk();
+        if (status_ == ZX_OK && handle_idx() != num_handles()) {
+            SetError("message did not contain the specified number of handles");
+        }
+    }
+
+    uint8_t* bytes() const { return bytes_; }
+    uint32_t num_bytes() const { return num_bytes_; }
+    uint32_t num_handles() const { return num_handles_; }
+
+    bool ValidateOutOfLineStorageClaim(const void* a, const void* b) {
+        return true;
+    }
+
+    void UnclaimedHandle(zx_handle_t* out_handle) {}
+    void ClaimedHandle(zx_handle_t* out_handle, uint32_t idx) {
+        if (out_handle != nullptr) {
+            *out_handle = handles_[idx];
+#ifdef __Fuchsia__
+        } else {
+            // Return value intentionally ignored: this is best-effort cleanup.
+            zx_handle_close(handles_[idx]);
+#endif
+        }
+    }
+
+    PointerState GetPointerState(const void* ptr) const {
+        return static_cast<PointerState>(*static_cast<const uintptr_t*>(ptr));
+    }
+    HandleState GetHandleState(zx_handle_t p) const {
+        return static_cast<HandleState>(p);
+    }
+
+    template <class T>
+    void UpdatePointer(T* p, T v) {
+        *p = v;
+    }
+
+    void SetError(const char* error_msg) {
+        status_ = ZX_ERR_INVALID_ARGS;
+        if (out_error_msg_ != nullptr) {
+            *out_error_msg_ = error_msg;
+        }
+#ifdef __Fuchsia__
+        if (handles_) {
+            // Return value intentionally ignored: this is best-effort cleanup.
+            zx_handle_close_many(handles_, num_handles());
+        }
+#endif
+    }
+
+    zx_status_t status() const { return status_; }
+
+private:
+    uint8_t* const bytes_;
+    const uint32_t num_bytes_;
+    const zx_handle_t* const handles_;
+    const uint32_t num_handles_;
+    const char** const out_error_msg_;
+    zx_status_t status_ = ZX_OK;
+};
+
+} // namespace
+
+zx_status_t fidl_decode(const fidl_type_t* type, void* bytes, uint32_t num_bytes,
+                        const zx_handle_t* handles, uint32_t num_handles,
+                        const char** out_error_msg) {
+    FidlDecoder decoder(type, bytes, num_bytes, handles, num_handles, out_error_msg);
+    decoder.Walk();
+    return decoder.status();
+}
+
+zx_status_t fidl_decode_msg(const fidl_type_t* type, fidl_msg_t* msg,
+                            const char** out_error_msg) {
+    return fidl_decode(type, msg->bytes, msg->num_bytes, msg->handles,
+                       msg->num_handles, out_error_msg);
+}
diff --git a/pkg/fidl/encoding.cpp b/pkg/fidl/encoding.cpp
new file mode 100644
index 0000000..f4d4f49
--- /dev/null
+++ b/pkg/fidl/encoding.cpp
@@ -0,0 +1,134 @@
+// Copyright 2017 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <lib/fidl/coding.h>
+
+#include <stdalign.h>
+#include <stdint.h>
+#include <stdlib.h>
+
+#include <lib/fidl/internal.h>
+#include <zircon/assert.h>
+#include <zircon/compiler.h>
+
+#ifdef __Fuchsia__
+#include <zircon/syscalls.h>
+#endif
+
+#include "buffer_walker.h"
+
+#include <stdio.h>
+
+// TODO(kulakowski) Design zx_status_t error values.
+
+namespace {
+
+class FidlEncoder final : public fidl::internal::BufferWalker<FidlEncoder, true, true> {
+    typedef fidl::internal::BufferWalker<FidlEncoder, true, true> Super;
+
+public:
+    FidlEncoder(const fidl_type_t* type, void* bytes, uint32_t num_bytes, zx_handle_t* handles,
+                uint32_t num_handles, uint32_t* out_actual_handles, const char** out_error_msg)
+        : Super(type), bytes_(static_cast<uint8_t*>(bytes)), num_bytes_(num_bytes),
+          handles_(handles), num_handles_(num_handles), out_actual_handles_(out_actual_handles),
+          out_error_msg_(out_error_msg) {}
+
+    void Walk() {
+        if (handles_ == nullptr && num_handles_ != 0u) {
+            SetError("Cannot provide non-zero handle count and null handle pointer");
+            return;
+        }
+        if (out_actual_handles_ == nullptr) {
+            SetError("Cannot encode with null out_actual_handles");
+            return;
+        }
+        Super::Walk();
+        if (status_ == ZX_OK) {
+            *out_actual_handles_ = handle_idx();
+        }
+    }
+
+    uint8_t* bytes() const { return bytes_; }
+    uint32_t num_bytes() const { return num_bytes_; }
+    uint32_t num_handles() const { return num_handles_; }
+
+    bool ValidateOutOfLineStorageClaim(const void* a, const void* b) {
+        return a == b;
+    }
+
+    void UnclaimedHandle(zx_handle_t* out_handle) {
+#ifdef __Fuchsia__
+        // Return value intentionally ignored: this is best-effort cleanup.
+        zx_handle_close(*out_handle);
+#endif
+    }
+    void ClaimedHandle(zx_handle_t* out_handle, uint32_t idx) {
+        assert(out_handle != nullptr);
+        handles_[idx] = *out_handle;
+        *out_handle = FIDL_HANDLE_PRESENT;
+    }
+
+    PointerState GetPointerState(const void* ptr) const {
+        return *static_cast<const uintptr_t*>(ptr) == 0
+                   ? PointerState::ABSENT
+                   : PointerState::PRESENT;
+    }
+    HandleState GetHandleState(zx_handle_t p) const {
+        return p == ZX_HANDLE_INVALID
+                   ? HandleState::ABSENT
+                   : HandleState::PRESENT;
+    }
+
+    template <class T>
+    void UpdatePointer(T** p, T* v) {
+        assert(*p == v);
+        assert(v != nullptr);
+        *p = reinterpret_cast<T*>(FIDL_ALLOC_PRESENT);
+    }
+
+    void SetError(const char* error_msg) {
+        if (status_ != ZX_OK) {
+            return;
+        }
+        status_ = ZX_ERR_INVALID_ARGS;
+        if (out_error_msg_ != nullptr) {
+            *out_error_msg_ = error_msg;
+        }
+#ifdef __Fuchsia__
+        if (handles_) {
+            // Return value intentionally ignored: this is best-effort cleanup.
+            zx_handle_close_many(handles_, num_handles());
+        }
+#endif
+    }
+
+    zx_status_t status() const { return status_; }
+
+private:
+    // Message state passed in to the constructor.
+    uint8_t* const bytes_;
+    const uint32_t num_bytes_;
+    zx_handle_t* const handles_;
+    const uint32_t num_handles_;
+    uint32_t* const out_actual_handles_;
+    const char** const out_error_msg_;
+    zx_status_t status_ = ZX_OK;
+};
+
+} // namespace
+
+zx_status_t fidl_encode(const fidl_type_t* type, void* bytes, uint32_t num_bytes,
+                        zx_handle_t* handles, uint32_t max_handles, uint32_t* out_actual_handles,
+                        const char** out_error_msg) {
+    FidlEncoder encoder(type, bytes, num_bytes, handles, max_handles, out_actual_handles,
+                        out_error_msg);
+    encoder.Walk();
+    return encoder.status();
+}
+
+zx_status_t fidl_encode_msg(const fidl_type_t* type, fidl_msg_t* msg,
+                            uint32_t* out_actual_handles, const char** out_error_msg) {
+    return fidl_encode(type, msg->bytes, msg->num_bytes, msg->handles, msg->num_handles,
+                       out_actual_handles, out_error_msg);
+}
diff --git a/pkg/fidl/epitaph.c b/pkg/fidl/epitaph.c
new file mode 100644
index 0000000..d1a14e1
--- /dev/null
+++ b/pkg/fidl/epitaph.c
@@ -0,0 +1,22 @@
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifdef __Fuchsia__
+
+#include <string.h>
+
+#include <lib/fidl/epitaph.h>
+#include <zircon/fidl.h>
+#include <zircon/syscalls.h>
+
+zx_status_t fidl_epitaph_write(zx_handle_t channel, zx_status_t error) {
+    fidl_epitaph_t epitaph;
+    memset(&epitaph, 0, sizeof(epitaph));
+    epitaph.hdr.ordinal = FIDL_EPITAPH_ORDINAL;
+    epitaph.hdr.reserved0 = error;
+
+    return zx_channel_write(channel, 0, &epitaph, sizeof(epitaph), NULL, 0);
+}
+
+#endif // __Fuchsia__
diff --git a/pkg/fidl/formatting.cpp b/pkg/fidl/formatting.cpp
new file mode 100644
index 0000000..ffe6f39
--- /dev/null
+++ b/pkg/fidl/formatting.cpp
@@ -0,0 +1,218 @@
+// Copyright 2017 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <lib/fidl/coding.h>
+
+#include <inttypes.h>
+#include <stdarg.h>
+#include <string.h>
+
+#include <lib/fidl/internal.h>
+#include <zircon/assert.h>
+#include <zircon/compiler.h>
+
+namespace {
+
+class StringBuilder {
+public:
+    StringBuilder(char* buffer, size_t capacity)
+        : buffer_(buffer), capacity_(capacity) {}
+
+    size_t length() const { return length_; }
+
+    void Append(const char* data, size_t length) {
+        size_t remaining = capacity_ - length_;
+        if (length > remaining) {
+            length = remaining;
+        }
+        memcpy(buffer_ + length_, data, length);
+        length_ += length;
+    }
+
+    void Append(const char* data) {
+        Append(data, strlen(data));
+    }
+
+    void AppendPrintf(const char* format, ...) __PRINTFLIKE(2, 3) {
+        va_list ap;
+        va_start(ap, format);
+        AppendVPrintf(format, ap);
+        va_end(ap);
+    }
+
+    void AppendVPrintf(const char* format, va_list ap) {
+        size_t remaining = capacity_ - length_;
+        if (remaining == 0u) {
+            return;
+        }
+        int count = vsnprintf(buffer_ + length_, remaining, format, ap);
+        if (count <= 0) {
+            return;
+        }
+        size_t length = static_cast<size_t>(count);
+        length_ += (length >= remaining ? remaining : length);
+    }
+
+private:
+    char* buffer_;
+    size_t capacity_;
+    size_t length_ = 0u;
+};
+
+void FormatNullability(StringBuilder* str, fidl::FidlNullability nullable) {
+    if (nullable == fidl::kNullable) {
+        str->Append("?");
+    }
+}
+
+void FormatStructName(StringBuilder* str, const fidl::FidlCodedStruct* coded_struct) {
+    if (coded_struct->name) {
+        str->Append(coded_struct->name);
+    } else {
+        str->Append("struct");
+    }
+}
+
+void FormatUnionName(StringBuilder* str, const fidl::FidlCodedUnion* coded_union) {
+    if (coded_union->name) {
+        str->Append(coded_union->name);
+    } else {
+        str->Append("union");
+    }
+}
+
+void FormatTypeName(StringBuilder* str, const fidl_type_t* type);
+void FormatElementName(StringBuilder* str, const fidl_type_t* type) {
+    if (type) {
+        FormatTypeName(str, type);
+    } else {
+        // TODO(jeffbrown): Print the actual primitive type name, assuming we
+        // start recording that information in the tables.
+        str->Append("primitive");
+    }
+}
+
+void FormatTypeName(StringBuilder* str, const fidl_type_t* type) {
+    switch (type->type_tag) {
+    case fidl::kFidlTypeStruct:
+        FormatStructName(str, &type->coded_struct);
+        break;
+    case fidl::kFidlTypeStructPointer:
+        FormatStructName(str, type->coded_struct_pointer.struct_type);
+        str->Append("?");
+        break;
+    case fidl::kFidlTypeUnion:
+        FormatUnionName(str, &type->coded_union);
+        break;
+    case fidl::kFidlTypeUnionPointer:
+        FormatUnionName(str, type->coded_union_pointer.union_type);
+        str->Append("?");
+        break;
+    case fidl::kFidlTypeArray:
+        str->Append("array<");
+        FormatElementName(str, type->coded_array.element);
+        str->Append(">");
+        str->AppendPrintf(":%" PRIu32, type->coded_array.array_size /
+                                           type->coded_array.element_size);
+        break;
+    case fidl::kFidlTypeString:
+        str->Append("string");
+        if (type->coded_string.max_size != FIDL_MAX_SIZE) {
+            str->AppendPrintf(":%" PRIu32, type->coded_string.max_size);
+        }
+        FormatNullability(str, type->coded_string.nullable);
+        break;
+    case fidl::kFidlTypeHandle:
+        str->Append("handle");
+        if (type->coded_handle.handle_subtype) {
+            str->Append("<");
+            switch (type->coded_handle.handle_subtype) {
+            case fidl::kFidlHandleSubtypeHandle:
+                str->Append("handle");
+                break;
+            case fidl::kFidlHandleSubtypeProcess:
+                str->Append("process");
+                break;
+            case fidl::kFidlHandleSubtypeThread:
+                str->Append("thread");
+                break;
+            case fidl::kFidlHandleSubtypeVmo:
+                str->Append("vmo");
+                break;
+            case fidl::kFidlHandleSubtypeChannel:
+                str->Append("channel");
+                break;
+            case fidl::kFidlHandleSubtypeEvent:
+                str->Append("event");
+                break;
+            case fidl::kFidlHandleSubtypePort:
+                str->Append("port");
+                break;
+            case fidl::kFidlHandleSubtypeInterrupt:
+                str->Append("interrupt");
+                break;
+            case fidl::kFidlHandleSubtypeLog:
+                str->Append("log");
+                break;
+            case fidl::kFidlHandleSubtypeSocket:
+                str->Append("socket");
+                break;
+            case fidl::kFidlHandleSubtypeResource:
+                str->Append("resource");
+                break;
+            case fidl::kFidlHandleSubtypeEventpair:
+                str->Append("eventpair");
+                break;
+            case fidl::kFidlHandleSubtypeJob:
+                str->Append("job");
+                break;
+            case fidl::kFidlHandleSubtypeVmar:
+                str->Append("vmar");
+                break;
+            case fidl::kFidlHandleSubtypeFifo:
+                str->Append("fifo");
+                break;
+            case fidl::kFidlHandleSubtypeGuest:
+                str->Append("guest");
+                break;
+            case fidl::kFidlHandleSubtypeTimer:
+                str->Append("timer");
+                break;
+            // TODO(pascallouis): Add support for iomap, pci, and hypervisor
+            // when they are supported in FIDL.
+            default:
+                str->AppendPrintf("%" PRIu32, type->coded_handle.handle_subtype);
+                break;
+            }
+            str->Append(">");
+        }
+        FormatNullability(str, type->coded_handle.nullable);
+        break;
+    case fidl::kFidlTypeVector:
+        str->Append("vector<");
+        FormatElementName(str, type->coded_vector.element);
+        str->Append(">");
+        if (type->coded_vector.max_count != FIDL_MAX_SIZE) {
+            str->AppendPrintf(":%" PRIu32, type->coded_vector.max_count);
+        }
+        FormatNullability(str, type->coded_vector.nullable);
+        break;
+    default:
+        ZX_PANIC("unrecognized tag");
+        break;
+    }
+}
+
+} // namespace
+
+size_t fidl_format_type_name(const fidl_type_t* type,
+                             char* buffer, size_t capacity) {
+    if (!type || !buffer || !capacity) {
+        return 0u;
+    }
+
+    StringBuilder str(buffer, capacity);
+    FormatTypeName(&str, type);
+    return str.length();
+}
diff --git a/pkg/fidl/handle_closing.cpp b/pkg/fidl/handle_closing.cpp
new file mode 100644
index 0000000..5350993
--- /dev/null
+++ b/pkg/fidl/handle_closing.cpp
@@ -0,0 +1,108 @@
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+
+#include <limits>
+#include <stdalign.h>
+#include <stdint.h>
+#include <stdlib.h>
+
+#include <lib/fidl/coding.h>
+
+#ifdef __Fuchsia__
+
+#include <lib/fidl/internal.h>
+#include <zircon/assert.h>
+#include <zircon/compiler.h>
+#include <zircon/syscalls.h>
+
+#include "buffer_walker.h"
+
+namespace {
+
+class FidlHandleCloser final : public fidl::internal::BufferWalker<FidlHandleCloser, true, true> {
+    typedef fidl::internal::BufferWalker<FidlHandleCloser, true, true> Super;
+
+public:
+    FidlHandleCloser(const fidl_type_t* type, void* bytes, uint32_t num_bytes,
+                     const char** out_error_msg)
+        : Super(type), bytes_(static_cast<uint8_t*>(bytes)), num_bytes_(num_bytes),
+          out_error_msg_(out_error_msg) {}
+
+    void Walk() {
+        Super::Walk();
+    }
+
+    uint8_t* bytes() const { return bytes_; }
+    uint32_t num_bytes() const { return num_bytes_; }
+    uint32_t num_handles() const { return std::numeric_limits<uint32_t>::max(); }
+
+    bool ValidateOutOfLineStorageClaim(const void* a, void* b) {
+        return true;
+    }
+
+    void UnclaimedHandle(zx_handle_t* out_handle) {
+        // This will never happen since we are returning numeric_limits::max() in num_handles.
+        // We want to claim (close) all the handles.
+        ZX_DEBUG_ASSERT(false);
+    }
+
+    void ClaimedHandle(zx_handle_t* out_handle, uint32_t idx) {
+        if (*out_handle != ZX_HANDLE_INVALID) {
+            zx_handle_close(*out_handle);
+        }
+        *out_handle = ZX_HANDLE_INVALID;
+    }
+
+    template <class T>
+    void UpdatePointer(T* const* p, T* v) {}
+
+    PointerState GetPointerState(const void* ptr) const {
+        return *static_cast<const uintptr_t*>(ptr) == 0
+               ? PointerState::ABSENT
+               : PointerState::PRESENT;
+    }
+
+    HandleState GetHandleState(zx_handle_t p) const {
+        // Treat all handles as present to keep the buffer walker going.
+        return HandleState::PRESENT;
+    }
+
+    void SetError(const char* error_msg) {
+        status_ = ZX_ERR_INVALID_ARGS;
+        if (out_error_msg_ != nullptr) {
+            *out_error_msg_ = error_msg;
+        }
+    }
+
+    zx_status_t status() const { return status_; }
+
+private:
+    // Message state passed in to the constructor.
+    uint8_t* const bytes_;
+    const uint32_t num_bytes_;
+    const char** const out_error_msg_;
+    zx_status_t status_ = ZX_OK;
+};
+
+} // namespace
+
+#endif  // __Fuchsia__
+
+zx_status_t fidl_close_handles(const fidl_type_t* type, void* bytes, uint32_t num_bytes,
+                               const char** out_error_msg) {
+#if __Fuchsia__
+    FidlHandleCloser handle_closer(type, bytes, num_bytes, out_error_msg);
+    handle_closer.Walk();
+    return handle_closer.status();
+#else
+    return ZX_OK;  // there can't be any handles on the host
+#endif
+}
+
+zx_status_t fidl_close_handles_msg(const fidl_type_t* type, const fidl_msg_t* msg,
+                                   const char** out_error_msg) {
+    return fidl_close_handles(type, msg->bytes, msg->num_bytes, out_error_msg);
+}
+
diff --git a/pkg/fidl/include/lib/fidl/coding.h b/pkg/fidl/include/lib/fidl/coding.h
new file mode 100644
index 0000000..f30fe94
--- /dev/null
+++ b/pkg/fidl/include/lib/fidl/coding.h
@@ -0,0 +1,60 @@
+// Copyright 2017 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef LIB_FIDL_CODING_H_
+#define LIB_FIDL_CODING_H_
+
+#include <zircon/compiler.h>
+#include <zircon/fidl.h>
+#include <zircon/types.h>
+
+__BEGIN_CDECLS
+
+// The maximum recursion depth the fidl encoder or decoder will
+// perform. Each nested aggregate type (structs, unions, arrays, or
+// vectors) counts as one step in the recursion depth.
+#define FIDL_RECURSION_DEPTH 32
+
+// See https://fuchsia.googlesource.com/docs/+/master/development/languages/fidl/languages/c.md#fidl_encode-fidl_encode_msg
+zx_status_t fidl_encode(const fidl_type_t* type, void* bytes, uint32_t num_bytes,
+                        zx_handle_t* handles, uint32_t max_handles,
+                        uint32_t* out_actual_handles, const char** out_error_msg);
+zx_status_t fidl_encode_msg(const fidl_type_t* type, fidl_msg_t* msg,
+                            uint32_t* out_actual_handles, const char** out_error_msg);
+
+// See https://fuchsia.googlesource.com/docs/+/master/development/languages/fidl/languages/c.md#fidl_decode-fidl_decode_msg
+zx_status_t fidl_decode(const fidl_type_t* type, void* bytes, uint32_t num_bytes,
+                        const zx_handle_t* handles, uint32_t num_handles,
+                        const char** error_msg_out);
+zx_status_t fidl_decode_msg(const fidl_type_t* type, fidl_msg_t* msg,
+                            const char** out_error_msg);
+
+// Validates an encoded message against the given |type|.
+//
+// The |bytes| are not modified.
+zx_status_t fidl_validate(const fidl_type_t* type, const void* bytes, uint32_t num_bytes,
+                          uint32_t num_handles, const char** error_msg_out);
+zx_status_t fidl_validate_msg(const fidl_type_t* type, const fidl_msg_t* msg,
+                              const char** out_error_msg);
+
+// Traverses a linearized FIDL message, closing all handles within it.
+// This function is a no-op on host side.
+//
+// Handle values in |bytes| are replaced with ZX_HANDLE_INVALID.
+zx_status_t fidl_close_handles(const fidl_type_t* type, void* bytes, uint32_t num_bytes,
+                               const char** out_error_msg);
+zx_status_t fidl_close_handles_msg(const fidl_type_t* type, const fidl_msg_t* msg,
+                                   const char** out_error_msg);
+
+// Stores the name of a fidl type into the provided buffer.
+// Truncates the name if it is too long to fit into the buffer.
+// Returns the number of characters written into the buffer.
+//
+// Note: This function does not write a trailing NUL.
+size_t fidl_format_type_name(const fidl_type_t* type,
+                             char* buffer, size_t capacity);
+
+__END_CDECLS
+
+#endif // LIB_FIDL_CODING_H_
diff --git a/pkg/fidl/include/lib/fidl/cpp/builder.h b/pkg/fidl/include/lib/fidl/cpp/builder.h
new file mode 100644
index 0000000..bc394c5
--- /dev/null
+++ b/pkg/fidl/include/lib/fidl/cpp/builder.h
@@ -0,0 +1,104 @@
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef LIB_FIDL_CPP_BUILDER_H_
+#define LIB_FIDL_CPP_BUILDER_H_
+
+#include <new>  // For placement new.
+#include <stdalign.h>
+#include <stdint.h>
+
+#include <lib/fidl/cpp/message_part.h>
+#include <zircon/compiler.h>
+#include <zircon/fidl.h>
+#include <zircon/types.h>
+
+namespace fidl {
+
+// Builder helps FIDL clients store decoded objects in a buffer.
+//
+// Objects are allocated sequentually in the buffer with appropriate alignment
+// for in-place encoding. The client is responsible for ordering the objects in
+// the buffer appropriately.
+class Builder {
+public:
+    // Creates a buffer without any storage.
+    Builder();
+
+    // Creates a buffer that stores objects in the given memory.
+    //
+    // The constructed |Builder| object does not take ownership of the given
+    // storage.
+    Builder(void* buffer, uint32_t capacity);
+    ~Builder();
+
+    Builder(const Builder& other) = delete;
+    Builder& operator=(const Builder& other) = delete;
+
+    Builder(Builder&& other);
+    Builder& operator=(Builder&& other);
+
+    // Allocates storage in the buffer of sufficient size to store an object of
+    // type |T|. The object must have alignment constraints that are compatible
+    // with FIDL messages.
+    //
+    // If there is insufficient storage in the builder's buffer, this method
+    // returns nullptr.
+    template <typename T>
+    T* New() {
+        static_assert(alignof(T) <= FIDL_ALIGNMENT, "");
+        static_assert(sizeof(T) <= ZX_CHANNEL_MAX_MSG_BYTES, "");
+        if (void* ptr = Allocate(sizeof(T)))
+            return new (ptr) T;
+        return nullptr;
+    }
+
+    // Allocates storage in the buffer of sufficient size to store |count|
+    // objects of type |T|. The object must have alignment constraints that are
+    // compatible with FIDL messages.
+    //
+    // If there is insufficient storage in the builder's buffer, this method
+    // returns nullptr.
+    template <typename T>
+    T* NewArray(uint32_t count) {
+        static_assert(alignof(T) <= FIDL_ALIGNMENT, "");
+        static_assert(sizeof(T) <= ZX_CHANNEL_MAX_MSG_BYTES, "");
+        if (sizeof(T) * static_cast<uint64_t>(count) > UINT32_MAX)
+            return nullptr;
+        if (void* ptr = Allocate(static_cast<uint32_t>(sizeof(T) * count)))
+            return new (ptr) T[count];
+        return nullptr;
+    }
+
+    // Completes the building and returns a |MesssagePart| containing the
+    // allocated objects.
+    //
+    // The allocated objects are placed in the returned buffer in the order in
+    // which they were allocated, with appropriate alignment for a FIDL message.
+    // The returned buffer's capacity cooresponds to the capacity originally
+    // provided to this builder in its constructor.
+    BytePart Finalize();
+
+    // Attaches the given storage to the |Builder|.
+    //
+    // The |Builder| object does not take ownership of the given storage. The
+    // next object will be allocated at the start of the buffer.
+    void Reset(void* buffer, uint32_t capacity);
+
+protected:
+    uint8_t* buffer() const { return buffer_; }
+    uint32_t capacity() const { return capacity_; }
+
+private:
+    // Returns |size| bytes of zeroed memory aligned to at least FIDL_ALIGNMENT
+    void* Allocate(uint32_t size);
+
+    uint32_t capacity_;
+    uint32_t at_;
+    uint8_t* buffer_;
+};
+
+} // namespace fidl
+
+#endif //  LIB_FIDL_CPP_BUILDER_H_
diff --git a/pkg/fidl/include/lib/fidl/cpp/message.h b/pkg/fidl/include/lib/fidl/cpp/message.h
new file mode 100644
index 0000000..d93e7c9
--- /dev/null
+++ b/pkg/fidl/include/lib/fidl/cpp/message.h
@@ -0,0 +1,172 @@
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef LIB_FIDL_CPP_MESSAGE_H_
+#define LIB_FIDL_CPP_MESSAGE_H_
+
+#include <lib/fidl/coding.h>
+#include <lib/fidl/cpp/message_part.h>
+#include <zircon/fidl.h>
+
+namespace fidl {
+
+// A FIDL message.
+//
+// A FIDL message has two parts: the bytes and the handles. The bytes are
+// divided into a header (of type fidl_message_header_t) and a payload, which
+// follows the header.
+//
+// A Message object does not own the storage for the message parts.
+class Message {
+public:
+    // Creates a message without any storage.
+    Message();
+
+    // Creates a message whose storage is backed by |bytes| and |handles|.
+    //
+    // The constructed |Message| object does not take ownership of the given
+    // storage, although does take ownership of zircon handles contained withing
+    // handles.
+    Message(BytePart bytes, HandlePart handles);
+
+    ~Message();
+
+    Message(const Message& other) = delete;
+    Message& operator=(const Message& other) = delete;
+
+    Message(Message&& other);
+    Message& operator=(Message&& other);
+
+    // Whether the message has enough bytes to contain a fidl_message_header_t.
+    bool has_header() const {
+        return bytes_.actual() >= sizeof(fidl_message_header_t);
+    }
+
+    // The header at the start of the message.
+    //
+    // Valid only if has_header().
+    const fidl_message_header_t& header() const {
+        return *reinterpret_cast<fidl_message_header_t*>(bytes_.data());
+    }
+    fidl_message_header_t& header() {
+        return *reinterpret_cast<fidl_message_header_t*>(bytes_.data());
+    }
+
+    // The transaction ID in the message header.
+    //
+    // Valid only if has_header().
+    zx_txid_t txid() const { return header().txid; }
+    void set_txid(zx_txid_t txid) { header().txid = txid; }
+
+    // The flags in the message header.
+    //
+    // Valid only if has_header().
+    uint32_t flags() const { return header().flags; }
+
+    // The flags in the message header.
+    //
+    // Valid only if has_header().
+    uint32_t ordinal() const { return header().ordinal; }
+
+    // The message payload that follows the header.
+    //
+    // Valid only if has_header().
+    BytePart payload() const {
+        constexpr uint32_t n = sizeof(fidl_message_header_t);
+        return BytePart(bytes_.data() + n, bytes_.capacity() - n, bytes_.actual() - n);
+    }
+
+    // The message bytes interpreted as the given type.
+    template <typename T>
+    T* GetBytesAs() const {
+        return reinterpret_cast<T*>(bytes_.data());
+    }
+
+    // The message payload that follows the header interpreted as the given type.
+    //
+    // Valid only if has_header().
+    template <typename T>
+    T* GetPayloadAs() const {
+        return reinterpret_cast<T*>(bytes_.data() + sizeof(fidl_message_header_t));
+    }
+
+    // The storage for the bytes of the message.
+    BytePart& bytes() { return bytes_; }
+    const BytePart& bytes() const { return bytes_; }
+    void set_bytes(BytePart bytes) { bytes_ = static_cast<BytePart&&>(bytes); }
+
+    // The storage for the handles of the message.
+    //
+    // When the message is encoded, the handle values are stored in this part of
+    // the message. When the message is decoded, this part of the message is
+    // empty and the handle values are stored in the bytes().
+    HandlePart& handles() { return handles_; }
+    const HandlePart& handles() const { return handles_; }
+
+    // Encodes the message in-place.
+    //
+    // The message must previously have been in a decoded state, for example,
+    // either by being built in a decoded state using a |Builder| or having been
+    // decoded using the |Decode| method.
+    zx_status_t Encode(const fidl_type_t* type, const char** error_msg_out);
+
+    // Decodes the message in-place.
+    //
+    // The message must previously have been in an encoded state, for example,
+    // either by being read from a zx_channel_t or having been encoded using the
+    // |Encode| method.
+    zx_status_t Decode(const fidl_type_t* type, const char** error_msg_out);
+
+    // Validates the message in-place.
+    //
+    // The message must already be in an encoded state, for example, either by
+    // being read from a zx_channel_t or having been created in that state.
+    //
+    // Does not modify the message.
+    zx_status_t Validate(const fidl_type_t* type, const char** error_msg_out) const;
+
+    // Read a message from the given channel.
+    //
+    // The bytes read from the channel are stored in bytes() and the handles
+    // read from the channel are stored in handles(). Existing data in these
+    // buffers is overwritten.
+    zx_status_t Read(zx_handle_t channel, uint32_t flags);
+
+    // Writes a message to the given channel.
+    //
+    // The bytes stored in bytes() are written to the channel and the handles
+    // stored in handles() are written to the channel.
+    //
+    // If this method returns ZX_OK, handles() will be empty because they were
+    // consumed by this operation.
+    zx_status_t Write(zx_handle_t channel, uint32_t flags);
+
+    // Issues a synchronous send and receive transaction on the given channel.
+    //
+    // The bytes stored in bytes() are written to the channel and the handles
+    // stored in handles() are written to the channel. The bytes read from the
+    // channel are stored in response->bytes() and the handles read from the
+    // channel are stored in response->handles().
+    //
+    // If this method returns ZX_OK, handles() will be empty because they were
+    // consumed by this operation.
+    zx_status_t Call(zx_handle_t channel, uint32_t flags, zx_time_t deadline,
+                     Message* response);
+
+    // Stop tracking the handles in stored in handles(), without closing them.
+    //
+    // Typically, these handles will be extracted during decode or the
+    // message's destructor, so this function will be unnecessary. However,
+    // for clients of ulib/fidl which decode message manually, this function
+    // is necessary to prevent extracted handles from being closed.
+    void ClearHandlesUnsafe();
+
+private:
+    BytePart bytes_;
+    HandlePart handles_;
+};
+
+} // namespace fidl
+
+#endif // LIB_FIDL_CPP_MESSAGE_H_
diff --git a/pkg/fidl/include/lib/fidl/cpp/message_buffer.h b/pkg/fidl/include/lib/fidl/cpp/message_buffer.h
new file mode 100644
index 0000000..8e85823
--- /dev/null
+++ b/pkg/fidl/include/lib/fidl/cpp/message_buffer.h
@@ -0,0 +1,58 @@
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef LIB_FIDL_CPP_MESSAGE_BUFFER_H_
+#define LIB_FIDL_CPP_MESSAGE_BUFFER_H_
+
+#include <stdint.h>
+
+#include <lib/fidl/cpp/builder.h>
+#include <lib/fidl/cpp/message.h>
+#include <zircon/fidl.h>
+#include <zircon/types.h>
+
+namespace fidl {
+
+class MessageBuffer {
+public:
+    // Creates a |MessageBuffer| that allocates buffers for message of the
+    // given capacities.
+    //
+    // The buffers are freed when the |MessageBuffer| is destructed.
+    explicit MessageBuffer(
+        uint32_t bytes_capacity = ZX_CHANNEL_MAX_MSG_BYTES,
+        uint32_t handles_capacity = ZX_CHANNEL_MAX_MSG_HANDLES);
+
+    // The memory that backs the message is freed by this destructor.
+    ~MessageBuffer();
+
+    // The memory in which bytes can be stored in this buffer.
+    uint8_t* bytes() const { return buffer_; }
+
+    // The total number of bytes that can be stored in this buffer.
+    uint32_t bytes_capacity() const { return bytes_capacity_; }
+
+    // The memory in which handles can be stored in this buffer.
+    zx_handle_t* handles() const;
+
+    // The total number of handles that can be stored in this buffer.
+    uint32_t handles_capacity() const { return handles_capacity_; }
+
+    // Creates a |Message| that is backed by the memory in this buffer.
+    //
+    // The returned |Message| contains no bytes or handles.
+    Message CreateEmptyMessage();
+
+    // Creates a |Builder| that is backed by the memory in this buffer.
+    Builder CreateBuilder();
+
+private:
+    uint8_t* const buffer_;
+    const uint32_t bytes_capacity_;
+    const uint32_t handles_capacity_;
+};
+
+} // namespace fidl
+
+#endif // LIB_FIDL_CPP_MESSAGE_BUFFER_H_
diff --git a/pkg/fidl/include/lib/fidl/cpp/message_builder.h b/pkg/fidl/include/lib/fidl/cpp/message_builder.h
new file mode 100644
index 0000000..b571f3b
--- /dev/null
+++ b/pkg/fidl/include/lib/fidl/cpp/message_builder.h
@@ -0,0 +1,76 @@
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef LIB_FIDL_CPP_MESSAGE_BUILDER_H_
+#define LIB_FIDL_CPP_MESSAGE_BUILDER_H_
+
+#include <stdint.h>
+
+#include <lib/fidl/cpp/builder.h>
+#include <lib/fidl/cpp/message_buffer.h>
+#include <lib/fidl/cpp/message.h>
+#include <zircon/fidl.h>
+#include <zircon/types.h>
+
+namespace fidl {
+
+// A builder for FIDL messages that owns the memory for the message.
+//
+// A |MessageBuilder| is a |Builder| that uses the heap to back the memory for
+// the message. If you wish to manage the memory yourself, you can use |Builder|
+// and |Message| directly.
+//
+// Upon creation, the |MessageBuilder| creates a FIDL message header, which you
+// can modify using |header()|.
+class MessageBuilder : public Builder {
+public:
+    // Creates a |MessageBuilder| for the given |type| that allocates buffers
+    // for message of the given capacities.
+    //
+    // The bytes buffer is initialied by adding a |fidl_message_header_t|
+    // header.
+    //
+    // The buffers are freed when the |MessageBuilder| is destructed.
+    explicit MessageBuilder(
+        const fidl_type_t* type,
+        uint32_t bytes_capacity = ZX_CHANNEL_MAX_MSG_BYTES,
+        uint32_t handles_capacity = ZX_CHANNEL_MAX_MSG_HANDLES);
+
+    // The memory that backs the message is freed by this destructor.
+    ~MessageBuilder();
+
+    // The type of the message payload this object is building.
+    const fidl_type_t* type() const { return type_; }
+
+    // The header for the message.
+    //
+    // The message header is allocated by the |MessageBuilder| itself.
+    fidl_message_header_t* header() const {
+        return reinterpret_cast<fidl_message_header_t*>(buffer());
+    }
+
+    // Encodes a message of the given |type|.
+    //
+    // The memory that backs the message returned by this function is owned by
+    // the |MessageBuilder|, which means the |MessageBuilder| must remain alive
+    // as long as the |Message| object is in use.
+    //
+    // The |message| parameter might be modified even if this method returns an
+    // error.
+    zx_status_t Encode(Message* message_out, const char** error_msg_out);
+
+    // Resets all the data in the |MessageBuffer|.
+    //
+    // The underlying buffer is retained and reused. The next object will be
+    // allocated at the start of the buffer.
+    void Reset();
+
+private:
+    const fidl_type_t* type_;
+    MessageBuffer buffer_;
+};
+
+} // namespace fidl
+
+#endif // LIB_FIDL_CPP_MESSAGE_BUILDER_H_
diff --git a/pkg/fidl/include/lib/fidl/cpp/message_part.h b/pkg/fidl/include/lib/fidl/cpp/message_part.h
new file mode 100644
index 0000000..1dd7f7b
--- /dev/null
+++ b/pkg/fidl/include/lib/fidl/cpp/message_part.h
@@ -0,0 +1,102 @@
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef LIB_FIDL_CPP_MESSAGE_PART_H_
+#define LIB_FIDL_CPP_MESSAGE_PART_H_
+
+#include <stdint.h>
+#include <string.h>
+
+#include <zircon/types.h>
+
+namespace fidl {
+
+// Part of a FIDL message.
+//
+// A FIDL message has two parts: the bytes and the handles. This class is used
+// to represent both kinds of parts.
+//
+// Each part of the message has a data buffer, which contains the actual data
+// for that part of the message, a capacity for that buffer, and the actual
+// amount of data stored in the buffer, which might be less that the capacity if
+// the buffer is not completely full.
+template<typename T>
+class MessagePart {
+public:
+    using value_type = T;
+    using const_iterator = const T*;
+
+    // A message part with no storage.
+    MessagePart() : data_(nullptr), capacity_(0u), actual_(0u) {}
+
+    // A message part that uses the given storage.
+    //
+    // The constructed |MessagePart| object does not take ownership of the given
+    // storage.
+    MessagePart(T* data, uint32_t capacity, uint32_t actual = 0u)
+        : data_(data), capacity_(capacity), actual_(actual) {}
+
+    MessagePart(const MessagePart& other) = delete;
+    MessagePart& operator=(const MessagePart& other) = delete;
+
+    MessagePart(MessagePart&& other)
+        : data_(other.data_),
+          capacity_(other.capacity_),
+          actual_(other.actual_) {
+        other.data_ = nullptr;
+        other.capacity_ = 0u;
+        other.actual_ = 0u;
+    }
+
+    MessagePart& operator=(MessagePart&& other) {
+        if (this == &other)
+            return *this;
+        data_ = other.data_;
+        capacity_ = other.capacity_;
+        actual_ = other.actual_;
+        other.data_ = nullptr;
+        other.capacity_ = 0u;
+        other.actual_ = 0u;
+        return *this;
+    }
+
+    // The data stored in this part of the message.
+    T* data() const { return data_; }
+
+    // The total amount of storage available for this part of the message.
+    //
+    // This part of the message might not actually use all of this storage. To
+    // determine how much storage is actually being used, see |actual()|.
+    uint32_t capacity() const { return capacity_; }
+
+    // The amount of storage that is actually being used for this part of the
+    // message.
+    //
+    // There might be more storage available than is actually being used. To
+    // determine how much storage is available, see |capacity()|.
+    uint32_t actual() const { return actual_; }
+    void set_actual(uint32_t actual) { actual_ = actual; }
+
+    T* begin() { return data_; }
+    const T* begin() const { return data_; }
+    const T* cbegin() const { return data_; }
+
+    T* end() { return data_ + actual_; }
+    const T* end() const { return data_ + actual_; }
+    const T* cend() const { return data_ + actual_; }
+
+    size_t size() const { return actual_; }
+
+private:
+    T* data_;
+    uint32_t capacity_;
+    uint32_t actual_;
+};
+
+using BytePart = MessagePart<uint8_t>;
+using HandlePart = MessagePart<zx_handle_t>;
+
+} // namespace fidl
+
+#endif // LIB_FIDL_CPP_MESSAGE_PART_H_
diff --git a/pkg/fidl/include/lib/fidl/cpp/string_view.h b/pkg/fidl/include/lib/fidl/cpp/string_view.h
new file mode 100644
index 0000000..88eec42
--- /dev/null
+++ b/pkg/fidl/include/lib/fidl/cpp/string_view.h
@@ -0,0 +1,46 @@
+// Copyright 2017 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef LIB_FIDL_CPP_STRING_VIEW_H_
+#define LIB_FIDL_CPP_STRING_VIEW_H_
+
+#include <zircon/fidl.h>
+
+namespace fidl {
+
+class StringView : public fidl_string_t {
+public:
+    StringView() : fidl_string_t{} {}
+
+    uint64_t size() const { return fidl_string_t::size; }
+    void set_size(uint64_t size) { fidl_string_t::size = size; }
+
+    const char* data() const { return fidl_string_t::data; }
+    void set_data(char* data) { fidl_string_t::data = data; }
+
+    char* mutable_data() const { return fidl_string_t::data; }
+
+    bool is_null() const { return fidl_string_t::data == nullptr; }
+    bool empty() const { return fidl_string_t::size == 0; }
+
+    const char& at(size_t offset) const { return data()[offset]; }
+    char& at(size_t offset) { return mutable_data()[offset]; }
+
+    const char& operator[](size_t offset) const { return at(offset); }
+    char& operator[](size_t offset) { return at(offset); }
+
+    char* begin() { return mutable_data(); }
+    const char* begin() const { return data(); }
+    const char* cbegin() const { return data(); }
+
+    char* end() { return mutable_data() + size(); }
+    const char* end() const { return data() + size(); }
+    const char* cend() const { return data() + size(); }
+
+    fidl_string_t* impl() { return this; }
+};
+
+} // namespace fidl
+
+#endif // LIB_FIDL_CPP_STRING_VIEW_H_
diff --git a/pkg/fidl/include/lib/fidl/cpp/vector_view.h b/pkg/fidl/include/lib/fidl/cpp/vector_view.h
new file mode 100644
index 0000000..df4cedf
--- /dev/null
+++ b/pkg/fidl/include/lib/fidl/cpp/vector_view.h
@@ -0,0 +1,47 @@
+// Copyright 2017 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef LIB_FIDL_CPP_VECTOR_VIEW_H_
+#define LIB_FIDL_CPP_VECTOR_VIEW_H_
+
+#include <zircon/fidl.h>
+
+namespace fidl {
+
+template<typename T>
+class VectorView : public fidl_vector_t {
+public:
+    VectorView() : fidl_vector_t{} {}
+
+    uint64_t count() const { return fidl_vector_t::count; }
+    void set_count(uint64_t count) { fidl_vector_t::count = count; }
+
+    const T* data() const { return static_cast<T*>(fidl_vector_t::data); }
+    void set_data(T* data) { fidl_vector_t::data = data; }
+
+    T* mutable_data() const { return static_cast<T*>(fidl_vector_t::data); }
+
+    bool is_null() const { return fidl_vector_t::data == nullptr; }
+    bool empty() const { return fidl_vector_t::count == 0; }
+
+    const T& at(size_t offset) const { return data()[offset]; }
+    T& at(size_t offset) { return mutable_data()[offset]; }
+
+    const T& operator[](size_t offset) const { return at(offset); }
+    T& operator[](size_t offset) { return at(offset); }
+
+    T* begin() { return mutable_data(); }
+    const T* begin() const { return data(); }
+    const T* cbegin() const { return data(); }
+
+    T* end() { return mutable_data() + count(); }
+    const T* end() const { return data() + count(); }
+    const T* cend() const { return data() + count(); }
+
+    fidl_vector_t* impl() { return this; }
+};
+
+} // namespace fidl
+
+#endif // LIB_FIDL_CPP_VECTOR_VIEW_H_
diff --git a/pkg/fidl/include/lib/fidl/epitaph.h b/pkg/fidl/include/lib/fidl/epitaph.h
new file mode 100644
index 0000000..55653a7
--- /dev/null
+++ b/pkg/fidl/include/lib/fidl/epitaph.h
@@ -0,0 +1,22 @@
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef LIB_FIDL_EPITAPH_H_
+#define LIB_FIDL_EPITAPH_H_
+
+#include <zircon/types.h>
+
+__BEGIN_CDECLS
+
+#ifdef __Fuchsia__
+
+// Sends an epitaph with the given values down the channel.
+// See https://fuchsia.googlesource.com/docs/+/master/development/languages/fidl/languages/c.md#fidl_epitaph_write
+zx_status_t fidl_epitaph_write(zx_handle_t channel, zx_status_t error);
+
+#endif // __Fuchsia__
+
+__END_CDECLS
+
+#endif // LIB_FIDL_EPITAPH_H_
diff --git a/pkg/fidl/include/lib/fidl/internal.h b/pkg/fidl/include/lib/fidl/internal.h
new file mode 100644
index 0000000..efef16e
--- /dev/null
+++ b/pkg/fidl/include/lib/fidl/internal.h
@@ -0,0 +1,242 @@
+// Copyright 2017 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef LIB_FIDL_INTERNAL_H_
+#define LIB_FIDL_INTERNAL_H_
+
+#include <assert.h>
+#include <stdint.h>
+
+#include <lib/fidl/coding.h>
+#include <zircon/syscalls/object.h>
+#include <zircon/types.h>
+
+// All sizes here are given as uint32_t. Fidl message sizes are bounded to well below UINT32_MAX.
+// This also applies to arrays and vectors. For arrays, element_count * element_size will always fit
+// with 32 bits. For vectors, max_count * element_size will always fit within 32 bits.
+
+// Pointers to other type tables within a type are always nonnull, with the exception of vectors.
+// In that case, a null pointer indicates that the element type of the vector has no interesting
+// information to be decoded (i.e. no pointers or handles). The vector type still needs to be
+// emitted as it contains the information about the size of its secondary object. Contrast this with
+// arrays: being inline, ones with no interesting coding information can be elided, just like a
+// uint32 field in a struct is elided.
+
+namespace fidl {
+
+enum FidlNullability : uint32_t {
+    kNonnullable = 0u,
+    kNullable = 1u,
+};
+
+inline uint64_t FidlAlign(uint32_t offset) {
+    constexpr uint64_t alignment_mask = FIDL_ALIGNMENT - 1;
+    return (offset + alignment_mask) & ~alignment_mask;
+}
+
+struct FidlField {
+    const fidl_type* type;
+    uint32_t offset;
+
+    constexpr FidlField(const fidl_type* type, uint32_t offset)
+        : type(type), offset(offset) {}
+};
+
+struct FidlTableField {
+    const fidl_type* type;
+    uint32_t ordinal;
+
+    constexpr FidlTableField(const fidl_type* type, uint32_t ordinal)
+        : type(type), ordinal(ordinal) {}
+};
+
+enum FidlTypeTag : uint32_t {
+    kFidlTypeStruct = 0u,
+    kFidlTypeStructPointer = 1u,
+    kFidlTypeTable = 8u,
+    kFidlTypeTablePointer = 9u,
+    kFidlTypeUnion = 2u,
+    kFidlTypeUnionPointer = 3u,
+    kFidlTypeArray = 4u,
+    kFidlTypeString = 5u,
+    kFidlTypeHandle = 6u,
+    kFidlTypeVector = 7u,
+};
+
+// Though the |size| is implied by the fields, computing that information is not the purview of this
+// library. It's easier for the compiler to stash it.
+struct FidlCodedStruct {
+    const FidlField* const fields;
+    const uint32_t field_count;
+    const uint32_t size;
+    const char* name; // may be nullptr if omitted at compile time
+
+    constexpr FidlCodedStruct(const FidlField* fields, uint32_t field_count, uint32_t size,
+                              const char* name)
+        : fields(fields), field_count(field_count), size(size), name(name) {}
+};
+
+struct FidlCodedStructPointer {
+    const FidlCodedStruct* const struct_type;
+
+    constexpr explicit FidlCodedStructPointer(const FidlCodedStruct* struct_type)
+        : struct_type(struct_type) {}
+};
+
+struct FidlCodedTable {
+    const FidlTableField* const fields;
+    const uint32_t field_count;
+    const char* name; // may be nullptr if omitted at compile time
+
+    constexpr FidlCodedTable(const FidlTableField* fields, uint32_t field_count,
+                             const char* name)
+        : fields(fields), field_count(field_count), name(name) {}
+};
+
+struct FidlCodedTablePointer {
+    const FidlCodedTable* const table_type;
+
+    constexpr explicit FidlCodedTablePointer(const FidlCodedTable* table_type)
+        : table_type(table_type) {}
+};
+
+// Unlike structs, union members do not have different offsets, so this points to an array of
+// |fidl_type*| rather than |FidlField|.
+//
+// On-the-wire unions begin with a tag which is an index into |types|.
+// |data_offset| is the offset of the data in the wire format (tag + padding).
+struct FidlCodedUnion {
+    const fidl_type* const* types;
+    const uint32_t type_count;
+    const uint32_t data_offset;
+    const uint32_t size;
+    const char* name; // may be nullptr if omitted at compile time
+
+    constexpr FidlCodedUnion(const fidl_type* const* types, uint32_t type_count,
+                             uint32_t data_offset, uint32_t size, const char* name)
+        : types(types), type_count(type_count), data_offset(data_offset), size(size), name(name) {}
+};
+
+struct FidlCodedUnionPointer {
+    const FidlCodedUnion* const union_type;
+
+    constexpr explicit FidlCodedUnionPointer(const FidlCodedUnion* union_type)
+        : union_type(union_type) {}
+};
+
+// An array is essentially a struct with |array_size / element_size| of the same field, named at
+// |element|.
+struct FidlCodedArray {
+    const fidl_type* const element;
+    const uint32_t array_size;
+    const uint32_t element_size;
+
+    constexpr FidlCodedArray(const fidl_type* element, uint32_t array_size, uint32_t element_size)
+        : element(element), array_size(array_size), element_size(element_size) {}
+};
+
+// Note: must keep in sync with fidlc types.h HandleSubtype.
+enum FidlHandleSubtype : zx_obj_type_t {
+    // special case to indicate subtype is not specified.
+    kFidlHandleSubtypeHandle = ZX_OBJ_TYPE_NONE,
+
+    kFidlHandleSubtypeProcess = ZX_OBJ_TYPE_PROCESS,
+    kFidlHandleSubtypeThread = ZX_OBJ_TYPE_THREAD,
+    kFidlHandleSubtypeVmo = ZX_OBJ_TYPE_VMO,
+    kFidlHandleSubtypeChannel = ZX_OBJ_TYPE_CHANNEL,
+    kFidlHandleSubtypeEvent = ZX_OBJ_TYPE_EVENT,
+    kFidlHandleSubtypePort = ZX_OBJ_TYPE_PORT,
+    kFidlHandleSubtypeInterrupt = ZX_OBJ_TYPE_INTERRUPT,
+    kFidlHandleSubtypeLog = ZX_OBJ_TYPE_LOG,
+    kFidlHandleSubtypeSocket = ZX_OBJ_TYPE_SOCKET,
+    kFidlHandleSubtypeResource = ZX_OBJ_TYPE_RESOURCE,
+    kFidlHandleSubtypeEventpair = ZX_OBJ_TYPE_EVENTPAIR,
+    kFidlHandleSubtypeJob = ZX_OBJ_TYPE_JOB,
+    kFidlHandleSubtypeVmar = ZX_OBJ_TYPE_VMAR,
+    kFidlHandleSubtypeFifo = ZX_OBJ_TYPE_FIFO,
+    kFidlHandleSubtypeGuest = ZX_OBJ_TYPE_GUEST,
+    kFidlHandleSubtypeTimer = ZX_OBJ_TYPE_TIMER,
+};
+
+struct FidlCodedHandle {
+    const zx_obj_type_t handle_subtype;
+    const FidlNullability nullable;
+
+    constexpr FidlCodedHandle(uint32_t handle_subtype, FidlNullability nullable)
+        : handle_subtype(handle_subtype), nullable(nullable) {}
+
+    static_assert(ZX_OBJ_TYPE_LAST <= UINT32_MAX, "");
+};
+
+struct FidlCodedString {
+    const uint32_t max_size;
+    const FidlNullability nullable;
+
+    constexpr FidlCodedString(uint32_t max_size, FidlNullability nullable)
+        : max_size(max_size), nullable(nullable) {}
+};
+
+// Note that |max_count * element_size| is guaranteed to fit into a uint32_t. Unlike other types,
+// the |element| pointer may be null. This occurs when the element type contains no interesting bits
+// (i.e. pointers or handles).
+struct FidlCodedVector {
+    const fidl_type* const element;
+    const uint32_t max_count;
+    const uint32_t element_size;
+    const FidlNullability nullable;
+
+    constexpr FidlCodedVector(const fidl_type* element, uint32_t max_count, uint32_t element_size,
+                              FidlNullability nullable)
+        : element(element), max_count(max_count), element_size(element_size), nullable(nullable) {}
+};
+
+} // namespace fidl
+
+struct fidl_type {
+    const fidl::FidlTypeTag type_tag;
+    const union {
+        const fidl::FidlCodedStruct coded_struct;
+        const fidl::FidlCodedStructPointer coded_struct_pointer;
+        const fidl::FidlCodedTable coded_table;
+        const fidl::FidlCodedTablePointer coded_table_pointer;
+        const fidl::FidlCodedUnion coded_union;
+        const fidl::FidlCodedUnionPointer coded_union_pointer;
+        const fidl::FidlCodedHandle coded_handle;
+        const fidl::FidlCodedString coded_string;
+        const fidl::FidlCodedArray coded_array;
+        const fidl::FidlCodedVector coded_vector;
+    };
+
+    constexpr fidl_type(fidl::FidlCodedStruct coded_struct)
+        : type_tag(fidl::kFidlTypeStruct), coded_struct(coded_struct) {}
+
+    constexpr fidl_type(fidl::FidlCodedStructPointer coded_struct_pointer)
+        : type_tag(fidl::kFidlTypeStructPointer), coded_struct_pointer(coded_struct_pointer) {}
+
+    constexpr fidl_type(fidl::FidlCodedTable coded_table)
+        : type_tag(fidl::kFidlTypeTable), coded_table(coded_table) {}
+
+    constexpr fidl_type(fidl::FidlCodedTablePointer coded_table_pointer)
+        : type_tag(fidl::kFidlTypeTablePointer), coded_table_pointer(coded_table_pointer) {}
+
+    constexpr fidl_type(fidl::FidlCodedUnion coded_union)
+        : type_tag(fidl::kFidlTypeUnion), coded_union(coded_union) {}
+
+    constexpr fidl_type(fidl::FidlCodedUnionPointer coded_union_pointer)
+        : type_tag(fidl::kFidlTypeUnionPointer), coded_union_pointer(coded_union_pointer) {}
+
+    constexpr fidl_type(fidl::FidlCodedHandle coded_handle)
+        : type_tag(fidl::kFidlTypeHandle), coded_handle(coded_handle) {}
+
+    constexpr fidl_type(fidl::FidlCodedString coded_string)
+        : type_tag(fidl::kFidlTypeString), coded_string(coded_string) {}
+
+    constexpr fidl_type(fidl::FidlCodedArray coded_array)
+        : type_tag(fidl::kFidlTypeArray), coded_array(coded_array) {}
+
+    constexpr fidl_type(fidl::FidlCodedVector coded_vector)
+        : type_tag(fidl::kFidlTypeVector), coded_vector(coded_vector) {}
+};
+
+#endif // LIB_FIDL_INTERNAL_H_
diff --git a/pkg/fidl/include/lib/fidl/llcpp/decoded_message.h b/pkg/fidl/include/lib/fidl/llcpp/decoded_message.h
new file mode 100644
index 0000000..52d0ec5
--- /dev/null
+++ b/pkg/fidl/include/lib/fidl/llcpp/decoded_message.h
@@ -0,0 +1,119 @@
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef LIB_FIDL_LLCPP_DECODED_MESSAGE_H_
+#define LIB_FIDL_LLCPP_DECODED_MESSAGE_H_
+
+#include <lib/fidl/coding.h>
+#include <lib/fidl/llcpp/encoded_message.h>
+#include <lib/fidl/llcpp/traits.h>
+#include <type_traits>
+#include <zircon/fidl.h>
+
+namespace fidl {
+
+// `DecodedMessage` manages a linearized FIDL message in decoded form.
+// It takes care of releasing all handles which were not consumed
+// (std::moved from the decoded FIDL struct) when it goes out of scope.
+template <typename FidlType>
+class DecodedMessage final {
+    static_assert(IsFidlType<FidlType>::value, "Only FIDL types allowed here");
+    static_assert(FidlType::MaxSize > 0, "Positive message size");
+
+public:
+    // Instantiates an empty message.
+    // To populate this message, decode from an EncodedMessage object.
+    DecodedMessage() = default;
+
+    // Instantiates a DecodedMessage which points to a buffer region with caller-managed memory.
+    // The buffer region is assumed to contain a linearized FIDL message with valid pointers.
+    // This does not take ownership of that buffer region.
+    // But it does take ownership of the handles within the buffer.
+    DecodedMessage(BytePart bytes) :
+        bytes_(std::move(bytes)) { }
+
+    DecodedMessage(DecodedMessage&& other) = default;
+
+    DecodedMessage& operator=(DecodedMessage&& other) = default;
+
+    DecodedMessage(const DecodedMessage& other) = delete;
+
+    DecodedMessage& operator=(const DecodedMessage& other) = delete;
+
+    ~DecodedMessage() {
+        CloseHandles();
+    }
+
+    // Keeps track of a new buffer region with caller-managed memory.
+    // The buffer region is assumed to contain a linearized FIDL message with valid pointers.
+    // This does not take ownership of that buffer region.
+    // But it does take ownership of the handles within the buffer.
+    void Reset(BytePart bytes) {
+        CloseHandles();
+        bytes_ = std::move(bytes);
+    }
+
+    // Consumes an encoded message object containing FIDL encoded bytes and handles.
+    // The current buffer region in DecodedMessage is always released.
+    // Uses the FIDL encoding tables to deserialize the message in-place.
+    // If the message is invalid, discards the buffer and returns an error.
+    zx_status_t DecodeFrom(EncodedMessage<FidlType>* msg, const char** out_error_msg) {
+        // Clear any existing message.
+        CloseHandles();
+        bytes_ = BytePart();
+        zx_status_t status = fidl_decode(FidlType::type,
+                                         msg->bytes().data(), msg->bytes().actual(),
+                                         msg->handles().data(), msg->handles().actual(),
+                                         out_error_msg);
+        // Clear out |msg| independent of success or failure
+        BytePart bytes = msg->ReleaseBytesAndHandles();
+        if (status == ZX_OK) {
+            Reset(std::move(bytes));
+        } else {
+            Reset(BytePart());
+        }
+        return status;
+    }
+
+    // Serializes the content of the message in-place and stores the result
+    // in |out_msg|. The message's contents are always consumed by this
+    // operation, even in case of an error.
+    zx_status_t EncodeTo(EncodedMessage<FidlType>* out_msg, const char** out_error_msg) {
+        return out_msg->Initialize([this, &out_error_msg] (BytePart& msg_bytes,
+                                                           HandlePart& msg_handles) {
+            msg_bytes = std::move(bytes_);
+            uint32_t actual_handles = 0;
+            zx_status_t status = fidl_encode(FidlType::type,
+                                             msg_bytes.data(), msg_bytes.actual(),
+                                             msg_handles.data(), msg_handles.capacity(),
+                                             &actual_handles, out_error_msg);
+            msg_handles.set_actual(actual_handles);
+            return status;
+        });
+    }
+
+    // Accesses the FIDL message by reinterpreting the buffer pointer.
+    // Returns nullptr if there is no message.
+    FidlType* message() const {
+        return reinterpret_cast<FidlType*>(bytes_.data());
+    }
+
+private:
+    // Use the FIDL encoding tables for |FidlType| to walk the message and
+    // destroy the handles it contains.
+    void CloseHandles() {
+#ifdef __Fuchsia__
+        if (bytes_.data()) {
+            fidl_close_handles(FidlType::type, bytes_.data(), bytes_.actual(), nullptr);
+        }
+#endif
+    }
+
+    // The contents of the decoded message.
+    BytePart bytes_;
+};
+
+}  // namespace fidl
+
+#endif // LIB_FIDL_LLCPP_DECODED_MESSAGE_H_
diff --git a/pkg/fidl/include/lib/fidl/llcpp/encoded_message.h b/pkg/fidl/include/lib/fidl/llcpp/encoded_message.h
new file mode 100644
index 0000000..8fd1a06
--- /dev/null
+++ b/pkg/fidl/include/lib/fidl/llcpp/encoded_message.h
@@ -0,0 +1,136 @@
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef LIB_FIDL_LLCPP_ENCODED_MESSAGE_H_
+#define LIB_FIDL_LLCPP_ENCODED_MESSAGE_H_
+
+#include <algorithm>
+#include <cstdint>
+#include <iterator>
+#include <lib/fidl/cpp/message_part.h>
+#include <lib/fidl/llcpp/traits.h>
+#include <lib/fit/traits.h>
+#include <type_traits>
+#include <utility>
+#include <zircon/fidl.h>
+
+#ifdef __Fuchsia__
+#include <zircon/syscalls.h>
+#endif
+
+namespace fidl {
+
+// Holds an encoded FIDL message, that is, a byte array plus a handle table.
+//
+// The bytes part points to an external caller-managed buffer, while the handles part
+// is owned by this class. Any handles will be closed upon destruction.
+// This class is aware of the upper bound on the number of handles
+// in a message, such that its size can be adjusted to fit the demands
+// of a specific FIDL type.
+//
+// Because this class does not own the underlying message buffer, the caller
+// must make sure the lifetime of this class does not extend over that of the buffer.
+template <typename FidlType>
+class EncodedMessage final {
+    static_assert(IsFidlType<FidlType>::value, "Only FIDL types allowed here");
+    static_assert(FidlType::MaxSize > 0, "Positive message size");
+
+public:
+    // Instantiates an empty buffer with no bytes or handles.
+    EncodedMessage() = default;
+
+    EncodedMessage(EncodedMessage&& other) noexcept {
+        if (this != &other) {
+            MoveImpl(std::move(other));
+        }
+    }
+
+    EncodedMessage& operator=(EncodedMessage&& other) noexcept {
+        if (this != &other) {
+            MoveImpl(std::move(other));
+        }
+        return *this;
+    }
+
+    EncodedMessage(const EncodedMessage& other) = delete;
+
+    EncodedMessage& operator=(const EncodedMessage& other) = delete;
+
+    // Instantiates an EncodedMessage which points to a buffer region with caller-managed memory.
+    // It does not take ownership of that buffer region.
+    // Also initializes an empty handles part.
+    EncodedMessage(BytePart bytes) :
+        bytes_(std::move(bytes)) { }
+
+    ~EncodedMessage() {
+        CloseHandles();
+    }
+
+    // Takes ownership of the contents of the message.
+    // The bytes and handle parts will become empty, while the existing bytes part is returned.
+    // The caller is responsible for having transferred the handles elsewhere
+    // before calling this method.
+    BytePart ReleaseBytesAndHandles() {
+        handles_.set_actual(0);
+        BytePart return_bytes = std::move(bytes_);
+        return return_bytes;
+    }
+
+    const BytePart& bytes() const { return bytes_; }
+
+    const HandlePart& handles() const { return handles_; }
+
+    // Clears the contents of the EncodedMessage then invokes Callback
+    // to initialize the EncodedMessage in-place then returns the callback's
+    // result.
+    //
+    // |callback| is a callable object whose arguments are (BytePart&, HandlePart&).
+    template <typename Callback>
+    decltype(auto) Initialize(Callback callback) {
+        static_assert(
+            fit::callable_traits<Callback>::args::size == 2 &&
+            std::is_same<
+                BytePart&,
+                typename fit::template callable_traits<Callback>::args::template at<0>>::value &&
+            std::is_same<
+                HandlePart&,
+                typename fit::template callable_traits<Callback>::args::template at<1>>::value,
+            "Callback signature must be: T(BytePart&, HandlePart&).");
+        bytes_ = BytePart();
+        CloseHandles();
+        return callback(bytes_, handles_);
+    }
+
+private:
+    void CloseHandles() {
+        if (handles_.actual() > 0) {
+#ifdef __Fuchsia__
+            zx_handle_close_many(handles_.data(), handles_.actual());
+#else
+            // How did we have handles if not on Fuchsia? Something bad happened...
+            assert(false);
+#endif
+            handles_.set_actual(0);
+        }
+    }
+
+    void MoveImpl(EncodedMessage&& other) noexcept {
+        CloseHandles();
+        bytes_ = std::move(other.bytes_);
+        // copy handles from |other|
+        memcpy(handle_storage_, other.handle_storage_,
+            other.handles_.actual() * sizeof(zx_handle_t));
+        // release handles in |other|
+        handles_.set_actual(other.handles().actual());
+        other.handles_.set_actual(0);
+    }
+
+    BytePart bytes_;
+    zx_handle_t handle_storage_[FidlType::MaxNumHandles];
+    HandlePart handles_{handle_storage_, FidlType::MaxNumHandles};
+};
+
+}
+
+#endif  // LIB_FIDL_LLCPP_ENCODED_MESSAGE_H_
diff --git a/pkg/fidl/include/lib/fidl/llcpp/traits.h b/pkg/fidl/include/lib/fidl/llcpp/traits.h
new file mode 100644
index 0000000..80fadd7
--- /dev/null
+++ b/pkg/fidl/include/lib/fidl/llcpp/traits.h
@@ -0,0 +1,67 @@
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef LIB_FIDL_LLCPP_TRAITS_H_
+#define LIB_FIDL_LLCPP_TRAITS_H_
+
+#include <lib/zx/object.h>
+#include <stdint.h>
+#include <type_traits>
+#include <zircon/fidl.h>
+
+// Defines type traits used in the low-level C++ binding.
+//
+// The contracts of a FIDL type |T| are as follows:
+//
+// |IsFidlType<T>| resolves to std::true_type.
+// |IsFidlMessage<T>| resolves to std::true_type iff |T| is a transactional message.
+// |T::MaxNumHandles| is an uint32_t specifying the upper bound on the number of contained handles.
+// |T::MaxSize| is an uint32_t specifying the upper bound on the message byte size.
+//              It is std::numeric_limits<uint32_t>::max() if |T| is unbounded.
+// |T::type| is a fidl_type_t* pointing to the corresponding encoding table, if any.
+//
+
+namespace fidl {
+
+// A type trait that indicates whether the given type is a request/response type
+// i.e. has a FIDL message header.
+template <typename T> struct IsFidlMessage : public std::false_type {};
+
+// Code-gen will explicitly conform the generated FIDL transactional messages to IsFidlMessage.
+
+// A type trait that indicates whether the given type is allowed to appear in
+// generated binding APIs and can be encoded/decoded.
+// As a start, all handle types are supported.
+template <typename T> struct IsFidlType :
+    public std::is_base_of<zx::object_base, T> {};
+
+// clang-format off
+// Specialize for primitives
+template <> struct IsFidlType<bool> : public std::true_type {};
+template <> struct IsFidlType<uint8_t> : public std::true_type {};
+template <> struct IsFidlType<uint16_t> : public std::true_type {};
+template <> struct IsFidlType<uint32_t> : public std::true_type {};
+template <> struct IsFidlType<uint64_t> : public std::true_type {};
+template <> struct IsFidlType<int8_t> : public std::true_type {};
+template <> struct IsFidlType<int16_t> : public std::true_type {};
+template <> struct IsFidlType<int32_t> : public std::true_type {};
+template <> struct IsFidlType<int64_t> : public std::true_type {};
+template <> struct IsFidlType<float> : public std::true_type {};
+template <> struct IsFidlType<double> : public std::true_type {};
+// clang-format on
+
+// String
+class StringView;
+template <> struct IsFidlType<StringView> : public std::true_type {};
+
+// Vector (conditional on element)
+template <typename E> class VectorView;
+template <typename E>
+struct IsFidlType<VectorView<E>> : public IsFidlType<E> {};
+
+// Code-gen will explicitly conform the generated FIDL structures to IsFidlType.
+
+}  // namespace fidl
+
+#endif // LIB_FIDL_LLCPP_TRAITS_H_
diff --git a/pkg/fidl/include/lib/fidl/transport.h b/pkg/fidl/include/lib/fidl/transport.h
new file mode 100644
index 0000000..2da0d9c
--- /dev/null
+++ b/pkg/fidl/include/lib/fidl/transport.h
@@ -0,0 +1,46 @@
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef LIB_FIDL_TRANSPORT_H_
+#define LIB_FIDL_TRANSPORT_H_
+
+#include <zircon/compiler.h>
+#include <zircon/types.h>
+
+__BEGIN_CDECLS
+
+// Writes |capacity| bytes from |buffer| to the control channel of |socket|.
+//
+// Blocks until |socket| is able to accept a control plane message.
+zx_status_t fidl_socket_write_control(zx_handle_t socket, const void* buffer,
+                                      size_t capacity);
+
+// Reads |capacity| bytes from the control channel of |socket| to |buffer|.
+//
+// Blocks until a control plane message is able to be read from |socket|.
+//
+// The actual number of bytes reads from the control plan is returned in
+// |out_actual|.
+zx_status_t fidl_socket_read_control(zx_handle_t socket, void* buffer,
+                                     size_t capacity, size_t* out_actual);
+
+// Issues a transaction on the control channel of |socket|.
+//
+// First, writes |capacity| bytes from |buffer| to the control channel of
+// |socket|. Second, reads |out_capacity| bytes from the control channel of
+// |socket| to |out_buffer|.
+//
+// Blocks until the transaction is complete.
+//
+// |buffer| and |out_buffer| may be aliased.
+//
+// The actual number of bytes reads from the control plan is returned in
+// |out_actual|.
+zx_status_t fidl_socket_call_control(zx_handle_t socket, const void* buffer,
+                                     size_t capacity, void* out_buffer,
+                                     size_t out_capacity, size_t* out_actual);
+
+__END_CDECLS
+
+#endif // LIB_FIDL_TRANSPORT_H_
diff --git a/pkg/fidl/message.cpp b/pkg/fidl/message.cpp
new file mode 100644
index 0000000..6857459
--- /dev/null
+++ b/pkg/fidl/message.cpp
@@ -0,0 +1,117 @@
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <lib/fidl/cpp/message.h>
+
+#include <string.h>
+
+#include <lib/fidl/coding.h>
+#include <lib/fidl/cpp/builder.h>
+
+#ifdef __Fuchsia__
+#include <zircon/syscalls.h>
+#endif
+
+namespace fidl {
+
+Message::Message() = default;
+
+Message::Message(BytePart bytes, HandlePart handles)
+    : bytes_(static_cast<BytePart&&>(bytes)),
+      handles_(static_cast<HandlePart&&>(handles)) {}
+
+Message::~Message() {
+#ifdef __Fuchsia__
+    zx_handle_close_many(handles_.data(), handles_.actual());
+#endif
+    ClearHandlesUnsafe();
+}
+
+Message::Message(Message&& other)
+    : bytes_(static_cast<BytePart&&>(other.bytes_)),
+      handles_(static_cast<HandlePart&&>(other.handles_)) {}
+
+Message& Message::operator=(Message&& other) {
+    bytes_ = static_cast<BytePart&&>(other.bytes_);
+    handles_ = static_cast<HandlePart&&>(other.handles_);
+    return *this;
+}
+
+zx_status_t Message::Encode(const fidl_type_t* type,
+                            const char** error_msg_out) {
+    uint32_t actual_handles = 0u;
+    zx_status_t status = fidl_encode(type, bytes_.data(), bytes_.actual(),
+                                     handles_.data(), handles_.capacity(),
+                                     &actual_handles, error_msg_out);
+    if (status == ZX_OK)
+        handles_.set_actual(actual_handles);
+    return status;
+}
+
+zx_status_t Message::Decode(const fidl_type_t* type,
+                            const char** error_msg_out) {
+    zx_status_t status = fidl_decode(type, bytes_.data(), bytes_.actual(),
+                                     handles_.data(), handles_.actual(),
+                                     error_msg_out);
+    ClearHandlesUnsafe();
+    return status;
+}
+
+zx_status_t Message::Validate(const fidl_type_t* type,
+                              const char** error_msg_out) const {
+    return fidl_validate(type, bytes_.data(), bytes_.actual(),
+                         handles_.actual(), error_msg_out);
+}
+
+#ifdef __Fuchsia__
+zx_status_t Message::Read(zx_handle_t channel, uint32_t flags) {
+    uint32_t actual_bytes = 0u;
+    uint32_t actual_handles = 0u;
+    zx_status_t status = zx_channel_read(
+        channel, flags, bytes_.data(), handles_.data(), bytes_.capacity(),
+        handles_.capacity(), &actual_bytes, &actual_handles);
+    if (status == ZX_OK) {
+        bytes_.set_actual(actual_bytes);
+        handles_.set_actual(actual_handles);
+    }
+    return status;
+}
+
+zx_status_t Message::Write(zx_handle_t channel, uint32_t flags) {
+    zx_status_t status = zx_channel_write(channel, flags, bytes_.data(),
+                                          bytes_.actual(), handles_.data(),
+                                          handles_.actual());
+    ClearHandlesUnsafe();
+    return status;
+}
+
+zx_status_t Message::Call(zx_handle_t channel, uint32_t flags,
+                          zx_time_t deadline, Message* response) {
+    zx_channel_call_args_t args;
+    args.wr_bytes = bytes_.data();
+    args.wr_handles = handles_.data();
+    args.rd_bytes = response->bytes_.data();
+    args.rd_handles = response->handles_.data();
+    args.wr_num_bytes = bytes_.actual();
+    args.wr_num_handles = handles_.actual();
+    args.rd_num_bytes = response->bytes_.capacity();
+    args.rd_num_handles = response->handles_.capacity();
+    uint32_t actual_bytes = 0u;
+    uint32_t actual_handles = 0u;
+    zx_status_t status = zx_channel_call(channel, flags, deadline, &args,
+                                         &actual_bytes, &actual_handles);
+    ClearHandlesUnsafe();
+    if (status == ZX_OK) {
+        response->bytes_.set_actual(actual_bytes);
+        response->handles_.set_actual(actual_handles);
+    }
+    return status;
+}
+#endif
+
+void Message::ClearHandlesUnsafe() {
+    handles_.set_actual(0u);
+}
+
+} // namespace fidl
diff --git a/pkg/fidl/message_buffer.cpp b/pkg/fidl/message_buffer.cpp
new file mode 100644
index 0000000..54e2346
--- /dev/null
+++ b/pkg/fidl/message_buffer.cpp
@@ -0,0 +1,50 @@
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <lib/fidl/cpp/message_buffer.h>
+#include <zircon/assert.h>
+
+#include <stdlib.h>
+
+namespace fidl {
+namespace {
+
+uint64_t AddPadding(uint32_t offset) {
+    constexpr uint32_t kMask = alignof(zx_handle_t) - 1;
+    // Cast before addition to avoid overflow.
+    return static_cast<uint64_t>(offset) + static_cast<uint64_t>(offset & kMask);
+}
+
+size_t GetAllocSize(uint32_t bytes_capacity, uint32_t handles_capacity) {
+    return AddPadding(bytes_capacity) + sizeof(zx_handle_t) * handles_capacity;
+}
+
+} // namespace
+
+MessageBuffer::MessageBuffer(uint32_t bytes_capacity,
+                             uint32_t handles_capacity)
+    : buffer_(static_cast<uint8_t*>(malloc(GetAllocSize(bytes_capacity, handles_capacity)))),
+      bytes_capacity_(bytes_capacity),
+      handles_capacity_(handles_capacity) {
+    ZX_ASSERT_MSG(buffer_, "malloc returned NULL in MessageBuffer::MessageBuffer()");
+}
+
+MessageBuffer::~MessageBuffer() {
+    free(buffer_);
+}
+
+zx_handle_t* MessageBuffer::handles() const {
+    return reinterpret_cast<zx_handle_t*>(buffer_ + AddPadding(bytes_capacity_));
+}
+
+Message MessageBuffer::CreateEmptyMessage() {
+    return Message(BytePart(bytes(), bytes_capacity()),
+                   HandlePart(handles(), handles_capacity()));
+}
+
+Builder MessageBuffer::CreateBuilder() {
+    return Builder(bytes(), bytes_capacity());
+}
+
+} // namespace fidl
diff --git a/pkg/fidl/message_builder.cpp b/pkg/fidl/message_builder.cpp
new file mode 100644
index 0000000..c178690
--- /dev/null
+++ b/pkg/fidl/message_builder.cpp
@@ -0,0 +1,35 @@
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <lib/fidl/cpp/message_builder.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+
+namespace fidl {
+
+MessageBuilder::MessageBuilder(const fidl_type_t* type,
+                               uint32_t bytes_capacity,
+                               uint32_t handles_capacity)
+    : type_(type),
+      buffer_(bytes_capacity, handles_capacity) {
+    Reset();
+}
+
+MessageBuilder::~MessageBuilder() = default;
+
+zx_status_t MessageBuilder::Encode(Message* message_out,
+                                   const char** error_msg_out) {
+    *message_out = Message(Finalize(),
+                           HandlePart(buffer_.handles(),
+                                      buffer_.handles_capacity()));
+    return message_out->Encode(type_, error_msg_out);
+}
+
+void MessageBuilder::Reset() {
+    Builder::Reset(buffer_.bytes(), buffer_.bytes_capacity());
+    New<fidl_message_header_t>();
+}
+
+} // namespace fidl
diff --git a/pkg/fidl/meta.json b/pkg/fidl/meta.json
new file mode 100644
index 0000000..be54c7d
--- /dev/null
+++ b/pkg/fidl/meta.json
@@ -0,0 +1,67 @@
+{
+  "banjo_deps": [], 
+  "deps": [], 
+  "fidl_deps": [], 
+  "files": [
+    "pkg/fidl/buffer_walker.h", 
+    "pkg/fidl/builder.cpp", 
+    "pkg/fidl/decoding.cpp", 
+    "pkg/fidl/encoding.cpp", 
+    "pkg/fidl/epitaph.c", 
+    "pkg/fidl/formatting.cpp", 
+    "pkg/fidl/handle_closing.cpp", 
+    "pkg/fidl/message.cpp", 
+    "pkg/fidl/message_buffer.cpp", 
+    "pkg/fidl/message_builder.cpp", 
+    "pkg/fidl/transport.cpp", 
+    "pkg/fidl/validating.cpp", 
+    "pkg/fidl/include/lib/fidl/coding.h", 
+    "pkg/fidl/include/lib/fidl/cpp/builder.h", 
+    "pkg/fidl/include/lib/fidl/cpp/message.h", 
+    "pkg/fidl/include/lib/fidl/cpp/message_buffer.h", 
+    "pkg/fidl/include/lib/fidl/cpp/message_builder.h", 
+    "pkg/fidl/include/lib/fidl/cpp/message_part.h", 
+    "pkg/fidl/include/lib/fidl/cpp/string_view.h", 
+    "pkg/fidl/include/lib/fidl/cpp/vector_view.h", 
+    "pkg/fidl/include/lib/fidl/epitaph.h", 
+    "pkg/fidl/include/lib/fidl/internal.h", 
+    "pkg/fidl/include/lib/fidl/llcpp/decoded_message.h", 
+    "pkg/fidl/include/lib/fidl/llcpp/encoded_message.h", 
+    "pkg/fidl/include/lib/fidl/llcpp/traits.h", 
+    "pkg/fidl/include/lib/fidl/transport.h"
+  ], 
+  "headers": [
+    "pkg/fidl/include/lib/fidl/coding.h", 
+    "pkg/fidl/include/lib/fidl/cpp/builder.h", 
+    "pkg/fidl/include/lib/fidl/cpp/message.h", 
+    "pkg/fidl/include/lib/fidl/cpp/message_buffer.h", 
+    "pkg/fidl/include/lib/fidl/cpp/message_builder.h", 
+    "pkg/fidl/include/lib/fidl/cpp/message_part.h", 
+    "pkg/fidl/include/lib/fidl/cpp/string_view.h", 
+    "pkg/fidl/include/lib/fidl/cpp/vector_view.h", 
+    "pkg/fidl/include/lib/fidl/epitaph.h", 
+    "pkg/fidl/include/lib/fidl/internal.h", 
+    "pkg/fidl/include/lib/fidl/llcpp/decoded_message.h", 
+    "pkg/fidl/include/lib/fidl/llcpp/encoded_message.h", 
+    "pkg/fidl/include/lib/fidl/llcpp/traits.h", 
+    "pkg/fidl/include/lib/fidl/transport.h"
+  ], 
+  "include_dir": "pkg/fidl/include", 
+  "name": "fidl", 
+  "root": "pkg/fidl", 
+  "sources": [
+    "pkg/fidl/buffer_walker.h", 
+    "pkg/fidl/builder.cpp", 
+    "pkg/fidl/decoding.cpp", 
+    "pkg/fidl/encoding.cpp", 
+    "pkg/fidl/epitaph.c", 
+    "pkg/fidl/formatting.cpp", 
+    "pkg/fidl/handle_closing.cpp", 
+    "pkg/fidl/message.cpp", 
+    "pkg/fidl/message_buffer.cpp", 
+    "pkg/fidl/message_builder.cpp", 
+    "pkg/fidl/transport.cpp", 
+    "pkg/fidl/validating.cpp"
+  ], 
+  "type": "cc_source_library"
+}
\ No newline at end of file
diff --git a/pkg/fidl/transport.cpp b/pkg/fidl/transport.cpp
new file mode 100644
index 0000000..253b5ec
--- /dev/null
+++ b/pkg/fidl/transport.cpp
@@ -0,0 +1,70 @@
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifdef __Fuchsia__
+
+#include <lib/fidl/transport.h>
+#include <zircon/assert.h>
+#include <zircon/syscalls.h>
+
+zx_status_t fidl_socket_write_control(zx_handle_t socket, const void* buffer,
+                                      size_t capacity) {
+    for (;;) {
+        zx_status_t status = zx_socket_write(socket, ZX_SOCKET_CONTROL, buffer,
+                                             capacity, nullptr);
+        if (status != ZX_ERR_SHOULD_WAIT) {
+            return status;
+        }
+
+        zx_signals_t observed = ZX_SIGNAL_NONE;
+        status = zx_object_wait_one(socket, ZX_SOCKET_CONTROL_WRITABLE | ZX_SOCKET_PEER_CLOSED,
+                                    ZX_TIME_INFINITE, &observed);
+        if (status != ZX_OK) {
+            return status;
+        }
+
+        if (observed & ZX_SOCKET_PEER_CLOSED) {
+            return ZX_ERR_PEER_CLOSED;
+        }
+
+        ZX_ASSERT(observed & ZX_SOCKET_CONTROL_WRITABLE);
+    }
+}
+
+zx_status_t fidl_socket_read_control(zx_handle_t socket, void* buffer,
+                                     size_t capacity, size_t* out_actual) {
+    for (;;) {
+        zx_status_t status = zx_socket_read(socket, ZX_SOCKET_CONTROL, buffer,
+                                            capacity, out_actual);
+        if (status != ZX_ERR_SHOULD_WAIT) {
+            return status;
+        }
+
+        zx_signals_t observed = ZX_SIGNAL_NONE;
+        status = zx_object_wait_one(socket, ZX_SOCKET_CONTROL_READABLE | ZX_SOCKET_PEER_CLOSED,
+                                    ZX_TIME_INFINITE, &observed);
+        if (status != ZX_OK) {
+            return status;
+        }
+
+        if (observed & ZX_SOCKET_CONTROL_READABLE) {
+            continue;
+        }
+
+        ZX_ASSERT(observed & ZX_SOCKET_PEER_CLOSED);
+        return ZX_ERR_PEER_CLOSED;
+    }
+}
+
+zx_status_t fidl_socket_call_control(zx_handle_t socket, const void* buffer,
+                                     size_t capacity, void* out_buffer,
+                                     size_t out_capacity, size_t* out_actual) {
+    zx_status_t status = fidl_socket_write_control(socket, buffer, capacity);
+    if (status != ZX_OK) {
+        return status;
+    }
+    return fidl_socket_read_control(socket, out_buffer, out_capacity, out_actual);
+}
+
+#endif
diff --git a/pkg/fidl/validating.cpp b/pkg/fidl/validating.cpp
new file mode 100644
index 0000000..342face
--- /dev/null
+++ b/pkg/fidl/validating.cpp
@@ -0,0 +1,90 @@
+// Copyright 2017 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <lib/fidl/coding.h>
+
+#include <stdalign.h>
+#include <stdint.h>
+#include <stdlib.h>
+
+#include <lib/fidl/internal.h>
+#include <zircon/assert.h>
+#include <zircon/compiler.h>
+
+#include "buffer_walker.h"
+
+// TODO(kulakowski) Design zx_status_t error values.
+
+namespace {
+
+class FidlValidator final : public fidl::internal::BufferWalker<FidlValidator, false, false> {
+    typedef fidl::internal::BufferWalker<FidlValidator, false, false> Super;
+
+public:
+    FidlValidator(const fidl_type_t* type, const void* bytes, uint32_t num_bytes,
+                  uint32_t num_handles, const char** out_error_msg)
+        : Super(type), bytes_(static_cast<const uint8_t*>(bytes)), num_bytes_(num_bytes),
+          num_handles_(num_handles), out_error_msg_(out_error_msg) {}
+
+    void Walk() {
+        Super::Walk();
+        if (status_ == ZX_OK && handle_idx() != num_handles()) {
+            SetError("message did not contain the specified number of handles");
+            return;
+        }
+    }
+
+    const uint8_t* bytes() const { return bytes_; }
+    uint32_t num_bytes() const { return num_bytes_; }
+    uint32_t num_handles() const { return num_handles_; }
+
+    bool ValidateOutOfLineStorageClaim(const void* a, const void* b) {
+        return true;
+    }
+
+    void UnclaimedHandle(const zx_handle_t* out_handle) {}
+    void ClaimedHandle(const zx_handle_t* out_handle, uint32_t idx) {}
+
+    template <class T>
+    void UpdatePointer(const T* const* p, const T* v) {}
+
+    PointerState GetPointerState(const void* ptr) const {
+        return static_cast<PointerState>(*static_cast<const uintptr_t*>(ptr));
+    }
+    HandleState GetHandleState(zx_handle_t p) const {
+        return static_cast<HandleState>(p);
+    }
+
+    void SetError(const char* error_msg) {
+        status_ = ZX_ERR_INVALID_ARGS;
+        if (out_error_msg_ != nullptr) {
+            *out_error_msg_ = error_msg;
+        }
+    }
+
+    zx_status_t status() const { return status_; }
+
+private:
+    // Message state passed in to the constructor.
+    const uint8_t* const bytes_;
+    const uint32_t num_bytes_;
+    const uint32_t num_handles_;
+    const char** const out_error_msg_;
+    zx_status_t status_ = ZX_OK;
+};
+
+} // namespace
+
+zx_status_t fidl_validate(const fidl_type_t* type, const void* bytes, uint32_t num_bytes,
+                          uint32_t num_handles, const char** out_error_msg) {
+    FidlValidator validator(type, bytes, num_bytes, num_handles, out_error_msg);
+    validator.Walk();
+    return validator.status();
+}
+
+zx_status_t fidl_validate_msg(const fidl_type_t* type, const fidl_msg_t* msg,
+                              const char** out_error_msg) {
+    return fidl_validate(type, msg->bytes, msg->num_bytes, msg->num_handles,
+                         out_error_msg);
+}
diff --git a/pkg/fidl_cpp/include/lib/fidl/cpp/binding.h b/pkg/fidl_cpp/include/lib/fidl/cpp/binding.h
new file mode 100644
index 0000000..05c0637
--- /dev/null
+++ b/pkg/fidl_cpp/include/lib/fidl/cpp/binding.h
@@ -0,0 +1,239 @@
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef LIB_FIDL_CPP_BINDING_H_
+#define LIB_FIDL_CPP_BINDING_H_
+
+#include <lib/async/dispatcher.h>
+#include <lib/fit/function.h>
+#include <lib/zx/channel.h>
+#include <zircon/assert.h>
+
+#include <memory>
+#include <utility>
+
+#include "lib/fidl/cpp/interface_handle.h"
+#include "lib/fidl/cpp/interface_ptr.h"
+#include "lib/fidl/cpp/interface_request.h"
+#include "lib/fidl/cpp/internal/stub_controller.h"
+
+namespace fidl {
+
+// Binds the implementation of |Interface| to a channel.
+//
+// The |Binding| listens for incoming messages on the channel, decodes them, and
+// calls the appropriate method on the bound implementation. If the message
+// expects a reply, the |Binding| creates callbacks that encode and send
+// reply messages when called.
+//
+// When the |Binding| object is destroyed, the binding between the channel
+// and the interface is torn down and the channel is closed, leaving the
+// |Binding| in an unbound state.
+//
+// The implementation pointer type of the binding is also parameterized,
+// allowing the use of smart pointer types such as |std::unique_ptr| to
+// reference the implementation.
+//
+// Example:
+//
+//   #include "foo.fidl.h"
+//
+//   class FooImpl : public Foo {
+//    public:
+//     explicit FooImpl(InterfaceRequest<Foo> request)
+//         : binding_(this, std::move(request)) {}
+//
+//     // Foo implementation here.
+//
+//    private:
+//     Binding<Foo> binding_;
+//   };
+//
+// After the |Binding| has been bound to an implementation, the implementation
+// will receive methods calls from the remote endpoint of the channel on the
+// async_t on which the |InterfaceRequest| was bound. By default this is the
+// thread on which the binding occurred.
+//
+// See also:
+//
+//  * |InterfacePtr|, which is the client analog of a |Binding|.
+template <typename Interface, typename ImplPtr = Interface*>
+class Binding {
+ public:
+  // Constructs an incomplete binding that will use the implementation |impl|.
+  //
+  // The binding may be completed with a subsequent call to the |Bind| method.
+  // Does not take ownership of |impl|, which must outlive the binding.
+  explicit Binding(ImplPtr impl)
+      : impl_(std::forward<ImplPtr>(impl)), stub_(&*this->impl()) {
+    controller_.set_stub(&stub_);
+    stub_.set_controller(&controller_);
+  }
+
+  // Constructs a completed binding of |channel| to implementation |impl|.
+  //
+  // Does not take ownership of |impl|, which must outlive the binding.
+  //
+  // If the |Binding| cannot be bound to the given |channel| (e.g., because
+  // the |channel| lacks |ZX_RIGHT_WAIT|), the |Binding| will be constructed
+  // in an unbound state.
+  //
+  // Uses the given async_dispatcher_t (e.g., a message loop) in order to read
+  // messages from the channel and to monitor the channel for
+  // |ZX_CHANNEL_PEER_CLOSED|.  If |dispatcher| is null, the current thread must
+  // have a default async_dispatcher_t.
+  Binding(ImplPtr impl, zx::channel channel,
+          async_dispatcher_t* dispatcher = nullptr)
+      : Binding(std::forward<ImplPtr>(impl)) {
+    Bind(std::move(channel), dispatcher);
+  }
+
+  // Constructs a completed binding of |impl| to the channel in |request|.
+  //
+  // Does not take ownership of |impl|, which must outlive the binding.
+  //
+  // If the |Binding| cannot be bound to the given |channel| (e.g., because
+  // the |channel| lacks |ZX_RIGHT_WAIT|), the |Binding| will be constructed
+  // in an unbound state.
+  //
+  // Uses the given async_dispatcher_t (e.g., a message loop) in order to read
+  // messages from the channel and to monitor the channel for
+  // |ZX_CHANNEL_PEER_CLOSED|.  If |dispatcher| is null, the current thread must
+  // have a default async_dispatcher_t.
+  Binding(ImplPtr impl, InterfaceRequest<Interface> request,
+          async_dispatcher_t* dispatcher = nullptr)
+      : Binding(std::forward<ImplPtr>(impl)) {
+    Bind(request.TakeChannel(), dispatcher);
+  }
+
+  Binding(const Binding&) = delete;
+  Binding& operator=(const Binding&) = delete;
+
+  // Completes a binding by creating a new channel, binding one endpoint to
+  // the previously specified implementation and returning the other endpoint.
+  //
+  // If |NewBinding| fails to create the underlying channel, the returned
+  // |InterfaceHandle| will return false from |is_valid()|.
+  //
+  // Uses the given async_dispatcher_t (e.g., a message loop) in order to read
+  // messages from the channel and to monitor the channel for
+  // |ZX_CHANNEL_PEER_CLOSED|.  If |dispatcher| is null, the current thread must
+  // have a default async_dispatcher_t.
+  InterfaceHandle<Interface> NewBinding(
+      async_dispatcher_t* dispatcher = nullptr) {
+    InterfaceHandle<Interface> client;
+    Bind(client.NewRequest().TakeChannel(), dispatcher);
+    return client;
+  }
+
+  // Binds the previously specified implementation to the given |channel|.
+  //
+  // If the |Binding| was prevously bound to another channel, that channel is
+  // closed.
+  //
+  // Uses the given async_dispatcher_t (e.g., a message loop) in order to read
+  // messages from the channel and to monitor the channel for
+  // |ZX_CHANNEL_PEER_CLOSED|.  If |dispatcher| is null, the current thread must
+  // have a default async_dispatcher_t.
+  //
+  // Returns an error if the binding was not able to be created (e.g., because
+  // the |channel| lacks |ZX_RIGHT_WAIT|).
+  zx_status_t Bind(zx::channel channel,
+                   async_dispatcher_t* dispatcher = nullptr) {
+    return controller_.reader().Bind(std::move(channel), dispatcher);
+  }
+
+  // Binds the previously specified implementation to the given
+  // |InterfaceRequest|.
+  //
+  // If the |Binding| was prevously bound to another channel, that channel is
+  // closed.
+  //
+  // Uses the given async_dispatcher_t (e.g., a message loop) in order to read
+  // messages from the channel and to monitor the channel for
+  // |ZX_CHANNEL_PEER_CLOSED|.  If |dispatcher| is null, the current thread must
+  // have a default async_dispatcher_t.
+  //
+  // Returns an error if the binding was not able to be created (e.g., because
+  // the |channel| lacks |ZX_RIGHT_WAIT|).
+  zx_status_t Bind(InterfaceRequest<Interface> request,
+                   async_dispatcher_t* dispatcher = nullptr) {
+    return Bind(request.TakeChannel(), dispatcher);
+  }
+
+  // Unbinds the underlying channel from this binding and returns it so it can
+  // be used in another context, such as on another thread or with a different
+  // implementation.
+  //
+  // After this function returns, the |Binding| is ready to be bound to another
+  // channel.
+  InterfaceRequest<Interface> Unbind() {
+    return InterfaceRequest<Interface>(controller_.reader().Unbind());
+  }
+
+  // Sends an Epitaph over the bound channel corresponding to the error passed
+  // as a parameter, closes the channel, and unbinds it.  An Epitaph is the last
+  // message sent over a channel before a close operation; for the purposes of
+  // this function, it can be thought of as a return code.  See the FIDL
+  // language spec for more information about Epitaphs.
+  //
+  // The return value can be any of the return values of zx_channel_write.
+  zx_status_t Close(zx_status_t epitaph_value) {
+    return controller_.reader().Close(epitaph_value);
+  }
+
+  // Blocks the calling thread until either a message arrives on the previously
+  // bound channel or an error occurs.
+  //
+  // Returns an error if waiting for the message, reading the message, or
+  // processing the message fails. If the error results in the channel being
+  // closed, the error handler will be called synchronously before this
+  // method returns.
+  //
+  // This method can be called only if this |Binding| is currently bound to a
+  // channel.
+  zx_status_t WaitForMessage() {
+    return controller_.reader().WaitAndDispatchOneMessageUntil(
+        zx::time::infinite());
+  }
+
+  // Sets an error handler that will be called if an error causes the underlying
+  // channel to be closed.
+  //
+  // If the error is being reported because an error occurred on the local side
+  // of the channel, the zx_status_t of that error will be passed as the
+  // parameter to the handler.
+  //
+  // If an Epitaph was present on the channel, its error value will be passed as
+  // the parameter.  See the FIDL language specification for more detail on
+  // Epitaphs.
+  //
+  // For example, the error handler will be called if the remote side of the
+  // channel sends an invalid message. When the error handler is called, the
+  // |Binding| will no longer be bound to the channel.
+  void set_error_handler(fit::function<void(zx_status_t)> error_handler) {
+    controller_.reader().set_error_handler(std::move(error_handler));
+  }
+
+  // The implementation used by this |Binding| to process incoming messages.
+  const ImplPtr& impl() const { return impl_; }
+
+  // The interface for sending events back to the client.
+  typename Interface::EventSender_& events() { return stub_; }
+
+  // Whether this |Binding| is currently listening to a channel.
+  bool is_bound() const { return controller_.reader().is_bound(); }
+
+  // The underlying channel.
+  const zx::channel& channel() const { return controller_.reader().channel(); }
+
+ private:
+  const ImplPtr impl_;
+  typename Interface::Stub_ stub_;
+  internal::StubController controller_;
+};
+
+}  // namespace fidl
+
+#endif  // LIB_FIDL_CPP_BINDING_H_
diff --git a/pkg/fidl_cpp/include/lib/fidl/cpp/binding_set.h b/pkg/fidl_cpp/include/lib/fidl/cpp/binding_set.h
new file mode 100644
index 0000000..c505344
--- /dev/null
+++ b/pkg/fidl_cpp/include/lib/fidl/cpp/binding_set.h
@@ -0,0 +1,156 @@
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef LIB_FIDL_CPP_BINDING_SET_H_
+#define LIB_FIDL_CPP_BINDING_SET_H_
+
+#include <algorithm>
+#include <memory>
+#include <utility>
+#include <vector>
+
+#include <lib/fit/function.h>
+
+#include "lib/fidl/cpp/binding.h"
+
+namespace fidl {
+
+// Manages a set of bindings to implementations owned by the bound channels.
+//
+// The implementation pointer type of the binding is also parameterized,
+// allowing the use of smart pointer types such as |std::unique_ptr<>| to
+// reference the implementation.
+//
+// See also:
+//
+//  * |InterfacePtrSet|, which is the client analog of |BindingSet|.
+template <typename Interface, typename ImplPtr = Interface*>
+class BindingSet {
+ public:
+  using Binding = ::fidl::Binding<Interface, ImplPtr>;
+  using StorageType = std::vector<std::unique_ptr<Binding>>;
+
+  using iterator = typename StorageType::iterator;
+
+  BindingSet() = default;
+
+  BindingSet(const BindingSet&) = delete;
+  BindingSet& operator=(const BindingSet&) = delete;
+
+  // Adds a binding to the set.
+  //
+  // The given |ImplPtr| is bound to the channel underlying the
+  // |InterfaceRequest|. The binding is removed (and the |~ImplPtr| called)
+  // when the created binding has an error (e.g., if the remote endpoint of
+  // the channel sends an invalid message).
+  //
+  // Whether this method takes ownership of |impl| depends on |ImplPtr|. If
+  // |ImplPtr| is a raw pointer, then this method does not take ownership of
+  // |impl|. If |ImplPtr| is a |unique_ptr|, then running |~ImplPtr| when the
+  // binding generates an error will delete |impl| because |~ImplPtr| is
+  // |~unique_ptr|, which deletes |impl|.
+  void AddBinding(ImplPtr impl, InterfaceRequest<Interface> request,
+                  async_dispatcher_t* dispatcher = nullptr) {
+    bindings_.push_back(std::make_unique<Binding>(
+        std::forward<ImplPtr>(impl), std::move(request), dispatcher));
+    auto* binding = bindings_.back().get();
+    // Set the connection error handler for the newly added Binding to be a
+    // function that will erase it from the vector.
+    binding->set_error_handler([binding, this](zx_status_t status) {
+      this->RemoveOnError(binding);
+    });
+  }
+
+  // Adds a binding to the set for the given implementation.
+  //
+  // Creates a channel for the binding and returns the client endpoint of
+  // the channel as an |InterfaceHandle|. If |AddBinding| fails to create the
+  // underlying channel, the returned |InterfaceHandle| will return false from
+  // |is_valid()|.
+  //
+  // The given |ImplPtr| is bound to the newly created channel. The binding is
+  // removed (and the |~ImplPtr| called) when the created binding has an error
+  // (e.g., if the remote endpoint of the channel sends an invalid message).
+  //
+  // Whether this method takes ownership of |impl| depends on |ImplPtr|. If
+  // |ImplPtr| is a raw pointer, then this method does not take ownership of
+  // |impl|. If |ImplPtr| is a |unique_ptr|, then running |~ImplPtr| when the
+  // binding generates an error will delete |impl| because |~ImplPtr| is
+  // |~unique_ptr|, which deletes |impl|.
+  InterfaceHandle<Interface> AddBinding(
+      ImplPtr impl, async_dispatcher_t* dispatcher = nullptr) {
+    InterfaceHandle<Interface> handle;
+    InterfaceRequest<Interface> request = handle.NewRequest();
+    if (!request)
+      return nullptr;
+    AddBinding(std::forward<ImplPtr>(impl), std::move(request), dispatcher);
+    return handle;
+  }
+
+  // Returns an InterfaceRequestHandler that binds the incoming
+  // InterfaceRequests this object.
+  InterfaceRequestHandler<Interface> GetHandler(
+      ImplPtr impl, async_dispatcher_t* dispatcher = nullptr) {
+    return [this, impl, dispatcher](InterfaceRequest<Interface> request) {
+      AddBinding(impl, std::move(request), dispatcher);
+    };
+  }
+
+  // Removes all the bindings from the set.
+  //
+  // Closes all the channels associated with this |BindingSet|.
+  // Bindings are destroyed AFTER it is removed from the bindings set. An
+  // example of when this is useful is if an error handler on a binding has
+  // some behavior where it needs to read from the binding set; the set would
+  // then properly reflect that the binding is not present in the set.
+  void CloseAll() {
+    auto bindings_local = std::move(bindings_);
+    bindings_.clear();
+  }
+
+  // The number of bindings in this |BindingSet|.
+  size_t size() const { return bindings_.size(); }
+
+  // Called when the last binding has been removed from this |BindingSet|.
+  //
+  // This function is not called by |CloseAll| or by |~BindingSet|.
+  void set_empty_set_handler(fit::closure empty_set_handler) {
+    empty_set_handler_ = std::move(empty_set_handler);
+  }
+
+  // The bindings stored in this set.
+  //
+  // This collection of bindings can be invalidated when a |Binding| in the
+  // set encounters a connection error because connection errors causes the
+  // |BindingSet| to remove the |Binding| from the set.
+  const StorageType& bindings() const { return bindings_; }
+
+ private:
+  // Called when a binding has an error to remove the binding from the set.
+  void RemoveOnError(Binding* binding) {
+    auto it = std::find_if(bindings_.begin(), bindings_.end(),
+                           [binding](const std::unique_ptr<Binding>& b) {
+                             return b.get() == binding;
+                           });
+    ZX_DEBUG_ASSERT(it != bindings_.end());
+
+    {
+      // Move ownership of binding out of storage, such that the binding is
+      // destroyed AFTER it is removed from the bindings.
+      auto binding_local = std::move(*it);
+      binding_local->set_error_handler(nullptr);
+      bindings_.erase(it);
+    }
+
+    if (bindings_.empty() && empty_set_handler_)
+      empty_set_handler_();
+  }
+
+  StorageType bindings_;
+  fit::closure empty_set_handler_;
+};
+
+}  // namespace fidl
+
+#endif  // LIB_FIDL_CPP_BINDING_SET_H_
diff --git a/pkg/fidl_cpp/include/lib/fidl/cpp/enum.h b/pkg/fidl_cpp/include/lib/fidl/cpp/enum.h
new file mode 100644
index 0000000..19ec1eb
--- /dev/null
+++ b/pkg/fidl_cpp/include/lib/fidl/cpp/enum.h
@@ -0,0 +1,21 @@
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef LIB_FIDL_CPP_ENUM_H_
+#define LIB_FIDL_CPP_ENUM_H_
+
+#include <type_traits>
+
+namespace fidl {
+
+// Converts an enum value to its underlying type.
+template <typename TEnum>
+constexpr auto ToUnderlying(TEnum value) ->
+    typename std::underlying_type<TEnum>::type {
+  return static_cast<typename std::underlying_type<TEnum>::type>(value);
+}
+
+}  // namespace fidl
+
+#endif  // LIB_FIDL_CPP_ENUM_H_
diff --git a/pkg/fidl_cpp/include/lib/fidl/cpp/interface_ptr.h b/pkg/fidl_cpp/include/lib/fidl/cpp/interface_ptr.h
new file mode 100644
index 0000000..e1af79a
--- /dev/null
+++ b/pkg/fidl_cpp/include/lib/fidl/cpp/interface_ptr.h
@@ -0,0 +1,305 @@
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef LIB_FIDL_CPP_INTERFACE_PTR_H_
+#define LIB_FIDL_CPP_INTERFACE_PTR_H_
+
+#include <algorithm>
+#include <cstddef>
+#include <utility>
+
+#include <lib/fit/function.h>
+#include <lib/zx/channel.h>
+#include <zircon/assert.h>
+
+#include "lib/fidl/cpp/interface_handle.h"
+#include "lib/fidl/cpp/interface_request.h"
+#include "lib/fidl/cpp/internal/proxy_controller.h"
+
+namespace fidl {
+
+// A client interface to a remote implementation of |Interface|.
+//
+// An |InterfacePtr| implements |Interface| by proxying calls through a
+// |channel| to a remote implementation of |Interface|. Method calls on the
+// |Interface| proxy are encoded and sent through the bound channel to the
+// remote endpoint, which processes them. If the remote endpoint has not yet
+// been bound to an implementation, messages sent on the channel are buffered
+// by the channel, allowing for *pipelined* operation.
+//
+// The |InterfacePtr| also keeps state about the connection and about
+// outstanding request transactions that are expecting replies. When a the
+// |InterfacePtr| receives a reply to an outstanding transaction, the
+// |InterfacePtr| decodes the reply and calls the appropriate callback on the
+// thread on which the |InterfacePtr| was bound.
+//
+// You need to bind the |InterfacePtr| before calling any |Interface| methods.
+// There are a number of ways to bind the |InterfacePtr|.  See |NewRequest|,
+// |Bind|, and the |Bind| method on |InterfaceHandle|.
+//
+// If the underlying channel experiences an error, the |InterfacePtr| will
+// unbind from the channel and call its error handler.
+//
+// This class is thread-hostile, as is the local proxy it manages. All calls to
+// this class or the proxy should be from the thread on which the
+// |InterfacePtr| was bound. If you need to move the proxy to a different
+// thread, extract the |InterfaceHandle| by calling |Unbind|, and pass the
+// |InterfaceHandle| to a different thread, which the |InterfaceHandle| can be
+// bound to an |InterfacePtr| again. This operation destroys the state about
+// outstanding request transactions that are expecting replies.
+//
+// See also:
+//
+//  * |Binding|, which is the server analog of an |InterfacePtr|.
+//  * |SynchronousInterfacePtr|, which is a synchronous client interface to a
+//    remote implementation.
+template <typename Interface>
+class InterfacePtr {
+ public:
+  using Proxy = typename Interface::Proxy_;
+
+  // Creates an unbound |InterfacePtr|.
+  InterfacePtr() : impl_(new Impl) {}
+  InterfacePtr(std::nullptr_t) : InterfacePtr() {}
+
+  InterfacePtr(const InterfacePtr& other) = delete;
+  InterfacePtr& operator=(const InterfacePtr& other) = delete;
+
+  InterfacePtr(InterfacePtr&& other) : impl_(std::move(other.impl_)) {
+    other.impl_.reset(new Impl);
+  }
+
+  InterfacePtr& operator=(InterfacePtr&& other) {
+    if (this != &other) {
+      impl_ = std::move(other.impl_);
+      other.impl_.reset(new Impl);
+    }
+    return *this;
+  }
+
+  // Bind the |InterfacePtr| to one endpoint of a newly created channel and
+  // return the other endpoint as an |InterfaceRequest|.
+  //
+  // Typically, the returned |InterfaceRequest| will be sent to a remote process
+  // to be bound to an implementation of |Interface| using a |Binding| object.
+  //
+  // After calling this method, clients can start calling methods on this
+  // |InterfacePtr|. The methods will write messages into the underlying
+  // channel created by |NewRequest|, where they will be buffered by the
+  // underlying channel until the |InterfaceRequest| is bound to an
+  // implementation of |Interface|, potentially in a remote process.
+  //
+  // Uses the given async_t (e.g., a message loop) in order to read messages
+  // from the channel and to monitor the channel for |ZX_CHANNEL_PEER_CLOSED|.
+  // If |dispatcher| is null, the current thread must have a default async_t.
+  //
+  // # Example
+  //
+  // Given the following interface:
+  //
+  //   interface Database {
+  //     OpenTable(request<Table> table);
+  //   };
+  //
+  // The client can use the |NewRequest| method to create the |InterfaceRequest|
+  // object needed by the |OpenTable| method:
+  //
+  //   DatabasePtr database = ...;  // Connect to database.
+  //   TablePtr table;
+  //   database->OpenTable(table.NewRequest());
+  //
+  // The client can call methods on |table| immediately.
+  InterfaceRequest<Interface> NewRequest(
+      async_dispatcher_t* dispatcher = nullptr) {
+    zx::channel h1;
+    zx::channel h2;
+    if (zx::channel::create(0, &h1, &h2) != ZX_OK ||
+        Bind(std::move(h1), dispatcher) != ZX_OK)
+      return nullptr;
+    return InterfaceRequest<Interface>(std::move(h2));
+  }
+
+  // Binds the |InterfacePtr| to the given |channel|.
+  //
+  // The |InterfacePtr| expects the remote end of the |channel| to speak the
+  // protocol defined by |Interface|. Unlike the |Bind| overload that takes a
+  // |InterfaceHandle| parameter, this |Bind| overload lacks type safety.
+  //
+  // If the |InterfacePtr| was prevously bound to another channel, that channel
+  // is closed. If the |channel| is invalid, then this method will effectively
+  // unbind the |InterfacePtr|. A more direct way to have that effect is to call
+  // |Unbind|.
+  //
+  // Uses the given async_t (e.g., a message loop) in order to read messages
+  // from the channel and to monitor the channel for |ZX_CHANNEL_PEER_CLOSED|.
+  // If |dispatcher| is null, the current thread must have a default async_t.
+  //
+  // Returns an error if the binding was not able to be created (e.g., because
+  // the |channel| lacks |ZX_RIGHT_WAIT|).
+  zx_status_t Bind(zx::channel channel,
+                   async_dispatcher_t* dispatcher = nullptr) {
+    return impl_->controller.reader().Bind(std::move(channel), dispatcher);
+  }
+
+  // Binds the |InterfacePtr| to the given |InterfaceHandle|.
+  //
+  // The |InterfacePtr| expects the remote end of the |channel| to speak the
+  // protocol defined by |Interface|. Unlike the |Bind| overload that takes a
+  // |channel| parameter, this |Bind| overload provides type safety.
+  //
+  // If the |InterfacePtr| was prevously bound to another channel, that channel
+  // is closed. If the |InterfaceHandle| is invalid, then this method will
+  // effectively unbind the |InterfacePtr|. A more direct way to have that
+  // effect is to call |Unbind|.
+  //
+  // Uses the given async_t (e.g., a message loop) in order to read messages
+  // from the channel and to monitor the channel for |ZX_CHANNEL_PEER_CLOSED|.
+  // If |dispatcher| is null, the current thread must have a default async_t.
+  //
+  // Returns an error if the binding was not able to be created (e.g., because
+  // the |channel| lacks |ZX_RIGHT_WAIT|).
+  zx_status_t Bind(InterfaceHandle<Interface> handle,
+                   async_dispatcher_t* dispatcher = nullptr) {
+    return Bind(handle.TakeChannel(), dispatcher);
+  }
+
+  // Unbinds the underlying channel from the |InterfacePtr|.
+  //
+  // The underlying channel is returned as an |InterfaceHandle|, which is safe
+  // to transport to another thread or process. Any callbacks waiting for
+  // replies from the remote endpoint are discarded and any outstanding
+  // transaction state is erased.
+  //
+  // After this method returns, a subsequent call to |Bind| is required before
+  // calling any additional |Interface| methods.
+  InterfaceHandle<Interface> Unbind() {
+    return InterfaceHandle<Interface>(impl_->controller.reader().Unbind());
+  }
+
+  // Whether this |InterfacePtr| is currently bound to a channel.
+  //
+  // If the |InterfacePtr| is bound to a channel, the |InterfacePtr| has
+  // affinity for the thread on which it was bound and calls to |Interface|
+  // methods are proxied to the remote endpoint of the channel.
+  //
+  // See also:
+  //
+  //  * |Bind|, which binds a channel to this |InterfacePtr|.
+  //  * |Unbind|, which unbinds a channel from this |InterfacePtr|.
+  bool is_bound() const { return impl_->controller.reader().is_bound(); }
+
+  // Whether this |InterfacePtr| is currently bound to a channel.
+  //
+  // See |is_bound| for details.
+  explicit operator bool() const { return is_bound(); }
+
+  // The |Interface| proxy associated with this |InterfacePtr|.
+  //
+  // When this |InterfacePtr| is bound, method calls on this |Interface| will
+  // be proxied to the remote endpoint of the connection. Methods that expect
+  // replies will retain the supplied callbacks until the |InterfacePtr| either
+  // receives a reply to that transaction or the |InterfacePtr| is unbound from
+  // the channel.
+  //
+  // When this |InterfacePtr| is not bound, it is an error to call methods on
+  // the returned |Interface|.
+  //
+  // The returned |Interface| is thread-hostile and can be used only on the
+  // thread on which the |InterfacePtr| was bound.
+  Interface* get() const { return &impl_->proxy; }
+  Interface* operator->() const { return get(); }
+  Interface& operator*() const { return *get(); }
+
+  // An object on which to register for FIDL events.
+  //
+  // Arriving events are dispatched to the callbacks stored on this object.
+  // Events for unbound callbacks are ignored.
+  Proxy& events() const { return impl_->proxy; }
+
+#ifdef FIDL_ENABLE_LEGACY_WAIT_FOR_RESPONSE
+
+  // DEPRECATED: Using InterfaceSyncPtr instead. If used in a test, consider
+  // spinning the async::Loop instead.
+  //
+  // Blocks the calling thread until either a message arrives on the previously
+  // bound channel or an error occurs.
+  //
+  // Returns an error if waiting for the message, reading the message, or
+  // processing the message fails. If the error results in the channel being
+  // closed, the error handler will be called synchronously before this
+  // method returns.
+  //
+  // This method can be called only if this |InterfacePtr| is currently bound to
+  // a channel.
+  zx_status_t WaitForResponse() {
+    return WaitForResponseUntil(zx::time::infinite());
+  }
+
+  // DEPRECATED: Using InterfaceSyncPtr instead. If used in a test, consider
+  // spinning the async::Loop instead.
+  //
+  // Blocks the calling thread until either a message arrives on the previously
+  // bound channel, an error occurs, or the |deadline| is exceeded.
+  //
+  // Returns ZX_ERR_TIMED_OUT if the deadline is exceeded.
+  //
+  // Returns an error if waiting for the message, reading the message, or
+  // processing the message fails. If the error results in the channel being
+  // closed, the error handler will be called synchronously before this
+  // method returns.
+  //
+  // This method can be called only if this |InterfacePtr| is currently bound to
+  // a channel.
+  zx_status_t WaitForResponseUntil(zx::time deadline) {
+    return impl_->controller.reader().WaitAndDispatchOneMessageUntil(deadline);
+  }
+#endif
+
+  // Sets an error handler that will be called if an error causes the underlying
+  // channel to be closed.
+  //
+  // If the error is being reported because an error occurred on the local side
+  // of the channel, the zx_status_t of that error will be passed as the
+  // parameter to the handler.
+  //
+  // If an Epitaph was present on the channel, its error value will be passed as
+  // the parameter.  See the FIDL language specification for more detail on
+  // Epitaphs.
+  //
+  // For example, the error handler will be called if the remote side of the
+  // channel sends an invalid message. When the error handler is called, the
+  // |Binding| will no longer be bound to the channel.
+  void set_error_handler(fit::function<void(zx_status_t)> error_handler) {
+    impl_->controller.reader().set_error_handler(std::move(error_handler));
+  }
+
+  // The underlying channel.
+  const zx::channel& channel() const {
+    return impl_->controller.reader().channel();
+  }
+
+  // Closes the channel and sends an Epitaph with the given error.  See the FIDL
+  // language spec for information about Epitaphs.
+  //
+  // The return value can be any of the return values of zx_channel_write.
+  zx_status_t Close(zx_status_t epitaph_value) {
+    return impl_->controller.reader().Close(epitaph_value);
+  }
+
+ private:
+  struct Impl;
+
+  std::unique_ptr<Impl> impl_;
+};
+
+template <typename T>
+struct InterfacePtr<T>::Impl {
+  Impl() : proxy(&controller) { controller.set_proxy(&proxy); }
+  internal::ProxyController controller;
+  mutable Proxy proxy;
+};
+
+}  // namespace fidl
+
+#endif  // LIB_FIDL_CPP_INTERFACE_PTR_H_
diff --git a/pkg/fidl_cpp/include/lib/fidl/cpp/interface_ptr_set.h b/pkg/fidl_cpp/include/lib/fidl/cpp/interface_ptr_set.h
new file mode 100644
index 0000000..8d54420
--- /dev/null
+++ b/pkg/fidl_cpp/include/lib/fidl/cpp/interface_ptr_set.h
@@ -0,0 +1,95 @@
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef LIB_FIDL_CPP_INTERFACE_PTR_SET_H_
+#define LIB_FIDL_CPP_INTERFACE_PTR_SET_H_
+
+#include <zircon/assert.h>
+#include <vector>
+
+#include "lib/fidl/cpp/interface_ptr.h"
+
+namespace fidl {
+
+// Contains a set of |InterfacePtr| objects, each with their own channels.
+//
+// An |InterfacePtr| is removed from the set and destroyed when its underlying
+// channel experiences an error. When the set is destroyed, all the underlying
+// channels are closed.
+//
+// An |InterfacePtrSet| is useful for broadcasting messages to a set of clients,
+// each with their own implementation of |Interface|.
+//
+// See also:
+//
+//  * |BindingSet|, which is the server analog of an |InterfacePtrSet|.
+template <typename Interface>
+class InterfacePtrSet {
+ public:
+  using StorageType = std::vector<std::unique_ptr<InterfacePtr<Interface>>>;
+  using Ptr = InterfacePtr<Interface>;
+
+  // Creates an empty |InterfacePtrSet|.
+  InterfacePtrSet() = default;
+
+  InterfacePtrSet(const InterfacePtrSet& other) = delete;
+  InterfacePtrSet& operator=(const InterfacePtrSet& other) = delete;
+
+  // Adds the given |InterfacePtr| to the set.
+  //
+  // The |InterfacePtr| must already be bound to a channel. The |InterfacePtr|
+  // will be removed from the set when its underlying channel experiences an
+  // error.
+  void AddInterfacePtr(InterfacePtr<Interface> ptr) {
+    ZX_DEBUG_ASSERT(ptr.is_bound());
+    // Allocated a new |InterfacePtr| so that we can have a unique value to use
+    // as a key for removing the InterfacePtr. Otherwise, we'll lose track of
+    // the InterfacePtr when the vector resizes.
+    ptrs_.push_back(std::make_unique<Ptr>(std::move(ptr)));
+    auto* pointer = ptrs_.back().get();
+    pointer->set_error_handler(
+        [pointer, this](zx_status_t status) { this->RemoveOnError(pointer); });
+  }
+
+  // The |InterfacePtr| objects stored in this set.
+  //
+  // This collection of bindings can be invalidated when an |InterfacePtr| in
+  // the set encounters a connection error because connection errors causes the
+  // |InterfacePtrSet| to remove the |InterfacePtr| from the set.
+  const StorageType& ptrs() const { return ptrs_; }
+
+  // Closes all channels associated with |InterfacePtr| objects in the set.
+  //
+  // After this method returns, the set is empty.
+  void CloseAll() { ptrs_.clear(); }
+
+  // The number of |InterfacePtr| objects in the set.
+  //
+  // This number might be smaller than the number of |InterfacePtr| objects
+  // added to the set if some of the underlying channels have experienced an
+  // error.
+  size_t size() const { return ptrs_.size(); }
+
+ private:
+  // Removes the given |pointer| from the set.
+  //
+  // Called from the error handler callback for |pointer|.
+  void RemoveOnError(Ptr* pointer) {
+    auto it = std::find_if(ptrs_.begin(), ptrs_.end(),
+                           [pointer](const std::unique_ptr<Ptr>& p) {
+                             return p.get() == pointer;
+                           });
+    ZX_DEBUG_ASSERT(it != ptrs_.end());
+    ptrs_.erase(it);
+  }
+
+  // We use |unique_ptr| rather than just |InterfacePtr| so that we can keep
+  // track of the |InterfacePtr| objects after the |vector| resizes and moves
+  // its contents to its new buffer.
+  StorageType ptrs_;
+};
+
+}  // namespace fidl
+
+#endif  // LIB_FIDL_CPP_INTERFACE_PTR_SET_H_
diff --git a/pkg/fidl_cpp/include/lib/fidl/cpp/internal/header.h b/pkg/fidl_cpp/include/lib/fidl/cpp/internal/header.h
new file mode 100644
index 0000000..60ec272
--- /dev/null
+++ b/pkg/fidl_cpp/include/lib/fidl/cpp/internal/header.h
@@ -0,0 +1,62 @@
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef LIB_FIDL_CPP_INTERNAL_HEADER_H_
+#define LIB_FIDL_CPP_INTERNAL_HEADER_H_
+
+#include <functional>
+#include <ostream>
+
+#include <lib/fidl/cpp/array.h>
+#include <lib/fit/function.h>
+
+#ifdef __Fuchsia__
+#include <lib/zx/bti.h>
+#include <lib/zx/channel.h>
+#include <lib/zx/debuglog.h>
+#include <lib/zx/event.h>
+#include <lib/zx/eventpair.h>
+#include <lib/zx/fifo.h>
+#include <lib/zx/guest.h>
+#include <lib/zx/handle.h>
+#include <lib/zx/interrupt.h>
+#include <lib/zx/job.h>
+#include <lib/zx/log.h>
+#include <lib/zx/object.h>
+#include <lib/zx/pmt.h>
+#include <lib/zx/port.h>
+#include <lib/zx/process.h>
+#include <lib/zx/profile.h>
+#include <lib/zx/resource.h>
+#include <lib/zx/socket.h>
+#include <lib/zx/suspend_token.h>
+#include <lib/zx/task.h>
+#include <lib/zx/thread.h>
+#include <lib/zx/time.h>
+#include <lib/zx/timer.h>
+#include <lib/zx/vcpu.h>
+#include <lib/zx/vmar.h>
+#include <lib/zx/vmo.h>
+#endif
+
+#include "lib/fidl/cpp/coding_traits.h"
+#include "lib/fidl/cpp/enum.h"
+
+#ifdef __Fuchsia__
+#include "lib/fidl/cpp/interface_ptr.h"
+#include "lib/fidl/cpp/internal/proxy_controller.h"
+#include "lib/fidl/cpp/internal/stub_controller.h"
+#include "lib/fidl/cpp/internal/synchronous_proxy.h"
+#include "lib/fidl/cpp/synchronous_interface_ptr.h"
+#endif
+
+#include "lib/fidl/cpp/string.h"
+#include "lib/fidl/cpp/vector.h"
+
+// clone.h must be imported before any of the generated Clone methods are
+// defined, so that calls to Clone in clone.h are referencing the ADL
+// implementation and are not ambiguous.
+#include "lib/fidl/cpp/clone.h"
+
+#endif  // LIB_FIDL_CPP_INTERNAL_HEADER_H_
diff --git a/pkg/fidl_cpp/include/lib/fidl/cpp/internal/implementation.h b/pkg/fidl_cpp/include/lib/fidl/cpp/internal/implementation.h
new file mode 100644
index 0000000..37a3bec
--- /dev/null
+++ b/pkg/fidl_cpp/include/lib/fidl/cpp/internal/implementation.h
@@ -0,0 +1,21 @@
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef LIB_FIDL_CPP_INTERNAL_IMPLEMENTATION_H_
+#define LIB_FIDL_CPP_INTERNAL_IMPLEMENTATION_H_
+
+#include <lib/fidl/internal.h>
+#include <stdint.h>
+#include <zircon/assert.h>
+
+#include <limits>
+#include <memory>
+
+#include "lib/fidl/cpp/clone.h"
+#include "lib/fidl/cpp/comparison.h"
+#include "lib/fidl/cpp/encoder.h"
+#include "lib/fidl/cpp/internal/logging.h"
+#include "lib/fidl/cpp/traits.h"
+
+#endif  // LIB_FIDL_CPP_INTERNAL_IMPLEMENTATION_H_
diff --git a/pkg/fidl_cpp/include/lib/fidl/cpp/internal/message_handler.h b/pkg/fidl_cpp/include/lib/fidl/cpp/internal/message_handler.h
new file mode 100644
index 0000000..13660ad
--- /dev/null
+++ b/pkg/fidl_cpp/include/lib/fidl/cpp/internal/message_handler.h
@@ -0,0 +1,39 @@
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef LIB_FIDL_CPP_INTERNAL_MESSAGE_HANDLER_H_
+#define LIB_FIDL_CPP_INTERNAL_MESSAGE_HANDLER_H_
+
+#include <lib/fidl/cpp/message.h>
+#include <zircon/types.h>
+
+namespace fidl {
+namespace internal {
+
+// An interface for receiving FIDL messages.
+//
+// Used by |MessageReader| to call back into its client whenever it reads a
+// message from the channel.
+class MessageHandler {
+ public:
+  virtual ~MessageHandler();
+
+  // A new message has arrived.
+  //
+  // The memory backing the message will remain valid until this method returns,
+  // at which point the memory might or might not be deallocated.
+  virtual zx_status_t OnMessage(Message message) = 0;
+
+  // The channel from which the messages were being read is gone.
+  //
+  // The channel's peer might have been closed or the |MessageReader| might have
+  // unbound from the channel. In either case, implementations that keep
+  // per-channel state should reset their state when this method is called.
+  virtual void OnChannelGone();
+};
+
+}  // namespace internal
+}  // namespace fidl
+
+#endif  // LIB_FIDL_CPP_INTERNAL_MESSAGE_HANDLER_H_
diff --git a/pkg/fidl_cpp/include/lib/fidl/cpp/internal/message_reader.h b/pkg/fidl_cpp/include/lib/fidl/cpp/internal/message_reader.h
new file mode 100644
index 0000000..5272231
--- /dev/null
+++ b/pkg/fidl_cpp/include/lib/fidl/cpp/internal/message_reader.h
@@ -0,0 +1,147 @@
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef LIB_FIDL_CPP_INTERNAL_MESSAGE_READER_H_
+#define LIB_FIDL_CPP_INTERNAL_MESSAGE_READER_H_
+
+#include <lib/async/wait.h>
+#include <lib/fidl/cpp/message.h>
+#include <lib/fidl/cpp/message_buffer.h>
+#include <lib/fit/function.h>
+#include <lib/zx/channel.h>
+
+#include <functional>
+#include <memory>
+#include <utility>
+
+#include "lib/fidl/cpp/internal/message_handler.h"
+
+namespace fidl {
+namespace internal {
+
+class MessageReader {
+ public:
+  explicit MessageReader(MessageHandler* message_handler = nullptr);
+  ~MessageReader();
+
+  MessageReader(const MessageReader&) = delete;
+  MessageReader& operator=(const MessageReader&) = delete;
+
+  // Binds the given channel to this |MessageReader|.
+  //
+  // The |MessageReader| will wait asynchronously for messages on this channel
+  // and dispatch them to the message handler using |dispatcher|. After this
+  // method returns, the |MessageReader| will be waiting for incomming messages.
+  //
+  // If the |MessageReader| is already bound, the |MessageReader| will first
+  // be unbound.
+  //
+  // If |dispatcher| is null, the current thread must have a default async_t.
+  zx_status_t Bind(zx::channel channel,
+                   async_dispatcher_t* dispatcher = nullptr);
+
+  // Unbinds the channel from this |MessageReader|.
+  //
+  // The |MessageReader| will stop waiting for the messages on this channel.
+  //
+  // Returns the channel to which this |MessageReader| was previously bound, if
+  // any.
+  zx::channel Unbind();
+
+  // Unbinds the channel from this |MessageReader| and clears the error handler.
+  void Reset();
+
+  // Unbinds the channel from |other| and bindings it to this |MessageReader|.
+  //
+  // Also moves the error handler from |other| to this |MessageReader|.
+  //
+  // Useful for implementing move semantics for objects that have a
+  // |MessageReader|.
+  zx_status_t TakeChannelAndErrorHandlerFrom(MessageReader* other);
+
+  // Sends an epitaph with the given value, unbinds, and then closes the channel
+  // associated with this |MessageReader|.
+  //
+  // The |MessageReader| will send an Epitaph with the given error, unbind
+  // the channel, and then close it.
+  //
+  // The return value can be any of the return values of zx_channel_write.
+  zx_status_t Close(zx_status_t epitaph_value);
+
+  // Whether the |MessageReader| is currently bound.
+  //
+  // See |Bind()| and |Unbind()|.
+  bool is_bound() const { return channel_.is_valid(); }
+
+  // The channel to which this |MessageReader| is bound, if any.
+  const zx::channel& channel() const { return channel_; }
+
+  // Synchronously waits on |channel()| until either a message is available or
+  // the peer closes. If the channel is readable, reads a single message from
+  // the channel and dispatches it to the message handler.
+  //
+  // Returns |ZX_ERR_BAD_STATE| if this |MessageReader| is not bound, or if it
+  // receives a malformed Epitaph.
+  zx_status_t WaitAndDispatchOneMessageUntil(zx::time deadline);
+
+  // The given message handler is called whenever the |MessageReader| reads a
+  // message from the channel.
+  //
+  // The |Message| given to the message handler will be valid until the message
+  // handler returns.
+  //
+  // The handler should return ZX_OK if the message was handled and an error
+  // otherwise. If the handler returns ZX_OK, the |MessageReader| will continue
+  // to wait for messages.
+  //
+  // The handler can destroy the |MessageReader|, in which case the
+  // handler MUST return |ZX_ERR_STOP|. If the handler returns
+  // |ZX_ERR_SHOULD_WAIT|, the |MessageReader| will continue waiting. Other
+  // errors cause the |MessageReader| to unbind from the channel and call the
+  // error handler.
+  void set_message_handler(MessageHandler* message_handler) {
+    message_handler_ = message_handler;
+  }
+
+  // The given error handler is called whenever the |MessageReader| encounters
+  // an error on the channel.
+  //
+  // If the error is being reported because an error occurred on the local side
+  // of the channel, the zx_status_t of that error will be passed as the
+  // parameter to the handler.
+  //
+  // If an Epitaph was present on the channel, its error value will be passed as
+  // the parameter.  See the FIDL language specification for more detail on
+  // Epitaphs.
+  //
+  // For example, the error handler will be called if the remote side of the
+  // channel sends an invalid message. When the error handler is called, the
+  // |Binding| will no longer be bound to the channel.
+  //
+  // The handler can destroy the |MessageReader|.
+  void set_error_handler(fit::function<void(zx_status_t)> error_handler) {
+    error_handler_ = std::move(error_handler);
+  }
+
+ private:
+  static void CallHandler(async_dispatcher_t* dispatcher, async_wait_t* wait,
+                          zx_status_t status, const zx_packet_signal_t* signal);
+  void OnHandleReady(async_dispatcher_t* dispatcher, zx_status_t status,
+                     const zx_packet_signal_t* signal);
+  zx_status_t ReadAndDispatchMessage(MessageBuffer* buffer);
+  void NotifyError(zx_status_t epitaph_value);
+  void Stop();
+
+  async_wait_t wait_;  // Must be first.
+  zx::channel channel_;
+  async_dispatcher_t* dispatcher_;
+  bool* should_stop_;  // See |Canary| in message_reader.cc.
+  MessageHandler* message_handler_;
+  fit::function<void(zx_status_t)> error_handler_;
+};
+
+}  // namespace internal
+}  // namespace fidl
+
+#endif  // LIB_FIDL_CPP_INTERNAL_MESSAGE_READER_H_
diff --git a/pkg/fidl_cpp/include/lib/fidl/cpp/internal/pending_response.h b/pkg/fidl_cpp/include/lib/fidl/cpp/internal/pending_response.h
new file mode 100644
index 0000000..125a7d8
--- /dev/null
+++ b/pkg/fidl_cpp/include/lib/fidl/cpp/internal/pending_response.h
@@ -0,0 +1,89 @@
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef LIB_FIDL_CPP_INTERNAL_PENDING_RESPONSE_H_
+#define LIB_FIDL_CPP_INTERNAL_PENDING_RESPONSE_H_
+
+#include <lib/fidl/cpp/message_builder.h>
+#include <zircon/types.h>
+
+namespace fidl {
+namespace internal {
+class WeakStubController;
+
+// A response to a FIDL message.
+//
+// When a server receives a message that expects a response, the stub receives a
+// |PendingResponse| object that the implementation can use to reply to the
+// message. A given |PendingResponse| object can be used to send a reply at
+// most once.
+//
+// If the |StubController| that processed the original message is destroyed or
+// unbound from the underlying channel (e.g., due to an error), the stub can
+// still safely call |Send|, but the response will not actually be sent to the
+// client.
+class PendingResponse {
+ public:
+  // Creates a |PendingResponse| that does not need a response.
+  //
+  // The |needs_response()| method will return false.
+  PendingResponse();
+
+  // Creates a |PendingResponse| for a message with the given transaction ID.
+  //
+  // The |PendingResponse| object will take a reference to |weak_controller|,
+  // which it releases in its destructor.
+  PendingResponse(zx_txid_t txid, WeakStubController* weak_controller);
+
+  ~PendingResponse();
+
+  // |PendingResponse| objects are copiable.
+  //
+  // Each copy refers to the same logical reponse, which means |Send| should be
+  // called at most once among all the copies.
+  //
+  // The reason |PendingResponse| objects are copiable is so that they can be
+  // held by an std::function, which is also copyable. Typically, a
+  // |PendingResponse| object is held as a member of another object that
+  // implements operator(), which can be wrapped by std::function.
+  PendingResponse(const PendingResponse& other);
+  PendingResponse& operator=(const PendingResponse& other);
+
+  // |PendingResponse| objects are movable.
+  //
+  // Moving a |PendingResponse| object is more efficient that copying it because
+  // moving avoid churning the reference count of the associated
+  // |WeakStubController|.
+  PendingResponse(PendingResponse&& other);
+  PendingResponse& operator=(PendingResponse&& other);
+
+  // Whether the message that caused this |PendingResponse| object to be created
+  // expects a response.
+  //
+  // This method does not indiciate whether a response has or has not already
+  // been sent. That state is difficult to track because |PendingResponse| is
+  // copiable.
+  bool needs_response() const { return txid_; }
+
+  // Send a response.
+  //
+  // This function should be called at most once among all the copies of a given
+  // |PendingResponse| object.
+  //
+  // If the associated |WeakStubController| is no longer available (e.g., if it
+  // has been destroyed), this function will return |ZX_ERR_BAD_STATE|.
+  zx_status_t Send(const fidl_type_t* type, Message message);
+
+ private:
+  // This class should be small enough to fit into the inline storage for an
+  // std::function to avoid allocating additional storage when processing
+  // messages. Currently, std::function has space for three pointers.
+  zx_txid_t txid_;
+  WeakStubController* weak_controller_;
+};
+
+}  // namespace internal
+}  // namespace fidl
+
+#endif  // LIB_FIDL_CPP_INTERNAL_PENDING_RESPONSE_H_
diff --git a/pkg/fidl_cpp/include/lib/fidl/cpp/internal/proxy.h b/pkg/fidl_cpp/include/lib/fidl/cpp/internal/proxy.h
new file mode 100644
index 0000000..cc72783
--- /dev/null
+++ b/pkg/fidl_cpp/include/lib/fidl/cpp/internal/proxy.h
@@ -0,0 +1,29 @@
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef LIB_FIDL_CPP_INTERNAL_PROXY_H_
+#define LIB_FIDL_CPP_INTERNAL_PROXY_H_
+
+#include <lib/fidl/cpp/message.h>
+#include <zircon/types.h>
+
+namespace fidl {
+namespace internal {
+
+// An interface for sending FIDL messages to a remote implementation.
+class Proxy {
+ public:
+  virtual ~Proxy();
+
+  // A new message has arrived.
+  //
+  // The memory backing the message will remain valid until this method returns,
+  // at which point the memory might or might not be deallocated.
+  virtual zx_status_t Dispatch_(Message message) = 0;
+};
+
+}  // namespace internal
+}  // namespace fidl
+
+#endif  // LIB_FIDL_CPP_INTERNAL_PROXY_H_
diff --git a/pkg/fidl_cpp/include/lib/fidl/cpp/internal/proxy_controller.h b/pkg/fidl_cpp/include/lib/fidl/cpp/internal/proxy_controller.h
new file mode 100644
index 0000000..070613f
--- /dev/null
+++ b/pkg/fidl_cpp/include/lib/fidl/cpp/internal/proxy_controller.h
@@ -0,0 +1,96 @@
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef LIB_FIDL_CPP_INTERNAL_PROXY_CONTROLLER_H_
+#define LIB_FIDL_CPP_INTERNAL_PROXY_CONTROLLER_H_
+
+#include <lib/fidl/cpp/message.h>
+#include <lib/fidl/cpp/message_builder.h>
+
+#include <map>
+#include <memory>
+
+#include "lib/fidl/cpp/internal/message_handler.h"
+#include "lib/fidl/cpp/internal/message_reader.h"
+#include "lib/fidl/cpp/internal/proxy.h"
+
+namespace fidl {
+namespace internal {
+
+// Controls the client endpoint of a FIDL channel.
+//
+// A |ProxyController| controls the protocol-specific "proxy" object. Proxy
+// objects are used on the client endpoint of a FIDL channel to encode messages
+// into the channel and send them to the server endpoint, whose "stub" object
+// decodes them and dispatches them to an implementation of the protocol.
+class ProxyController : public MessageHandler {
+ public:
+  ProxyController();
+  ~ProxyController();
+
+  ProxyController(const ProxyController&) = delete;
+  ProxyController& operator=(const ProxyController&) = delete;
+
+  ProxyController(ProxyController&&);
+  ProxyController& operator=(ProxyController&&);
+
+  // The |MessageReader| that is listening for responses to messages sent by
+  // this object.
+  MessageReader& reader() { return reader_; }
+  const MessageReader& reader() const { return reader_; }
+
+  // The protocol-specific object that decodes messages and dispatches them to
+  // an implementation of the protocol.
+  //
+  // The proxy must be set to a non-null value before messages are read from the
+  // underlying channel. Typically, the caller will set a non-null proxy before
+  // binding a channel to the |MessageReader|.
+  Proxy* proxy() const { return proxy_; }
+  void set_proxy(Proxy* proxy) { proxy_ = proxy; }
+
+  // Send a message over the channel.
+  //
+  // If |response_handler| is non-null, the message will be assigned a
+  // transaction identifier before being encoded and sent over the channel. The
+  // |response_handler| will be retained by the |ProxyController| until the
+  // |ProxyController| recieves a response to the message, at which time the
+  // |ProxyController| will call the |OnMessage| method of the
+  // |response_handler|.
+  //
+  // Returns an error if the message fails to encode properly or if the message
+  // cannot be written to the channel.
+  zx_status_t Send(const fidl_type_t* type, Message message,
+                   std::unique_ptr<MessageHandler> response_handler);
+
+  // Clears all the state associated with this |ProxyController|.
+  //
+  // After this method returns, the |ProxyController| is in the same state it
+  // would have been in if freshly constructed.
+  void Reset();
+
+ private:
+  // Called by the |MessageReader| when a message arrives on the channel from
+  // the server.
+  //
+  // The message might be a response to a previously sent message or an
+  // unsolicited event.
+  zx_status_t OnMessage(Message message) final;
+
+  // Causes the |ProxyController| to |ClearPendingHandlers()|.
+  void OnChannelGone() final;
+
+  // Causes the |ProxyController| to destroy all pending response handlers and
+  // reset its transition identifiers.
+  void ClearPendingHandlers();
+
+  MessageReader reader_;
+  Proxy* proxy_ = nullptr;
+  std::map<zx_txid_t, std::unique_ptr<MessageHandler>> handlers_;
+  zx_txid_t next_txid_;
+};
+
+}  // namespace internal
+}  // namespace fidl
+
+#endif  // LIB_FIDL_CPP_INTERNAL_PROXY_CONTROLLER_H_
diff --git a/pkg/fidl_cpp/include/lib/fidl/cpp/internal/stub.h b/pkg/fidl_cpp/include/lib/fidl/cpp/internal/stub.h
new file mode 100644
index 0000000..448f995
--- /dev/null
+++ b/pkg/fidl_cpp/include/lib/fidl/cpp/internal/stub.h
@@ -0,0 +1,51 @@
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef LIB_FIDL_CPP_INTERNAL_STUB_H_
+#define LIB_FIDL_CPP_INTERNAL_STUB_H_
+
+#include <lib/fidl/cpp/message.h>
+#include <zircon/types.h>
+
+#include "lib/fidl/cpp/internal/pending_response.h"
+
+namespace fidl {
+namespace internal {
+class StubController;
+
+// An interface for dispatching FIDL messages to a protocol implementation.
+//
+// Used by |StubController| to supply both a |Message| and a |PendingResponse|
+// object to protocol implementations.
+class Stub {
+ public:
+  virtual ~Stub();
+
+  // A new message has arrived.
+  //
+  // If the message expects a response, the |PendingResponse| object's
+  // |needs_response()| method will return true.
+  //
+  // The memory backing the message will remain valid until this method returns,
+  // at which point the memory might or might not be deallocated.
+  //
+  // The |PendingResponse| object has affinity for the current thread and is not
+  // safe to transport to another thread.
+  virtual zx_status_t Dispatch_(Message message, PendingResponse response) = 0;
+
+  // The protocol-agnostic object that listens for incoming messages.
+  //
+  // The controller must be set to a non-null value before sending events
+  // through this stub.
+  StubController* controller() const { return controller_; }
+  void set_controller(StubController* controller) { controller_ = controller; }
+
+ private:
+  StubController* controller_ = nullptr;
+};
+
+}  // namespace internal
+}  // namespace fidl
+
+#endif  // LIB_FIDL_CPP_INTERNAL_STUB_H_
diff --git a/pkg/fidl_cpp/include/lib/fidl/cpp/internal/stub_controller.h b/pkg/fidl_cpp/include/lib/fidl/cpp/internal/stub_controller.h
new file mode 100644
index 0000000..d89729e
--- /dev/null
+++ b/pkg/fidl_cpp/include/lib/fidl/cpp/internal/stub_controller.h
@@ -0,0 +1,80 @@
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef LIB_FIDL_CPP_INTERNAL_STUB_CONTROLLER_H_
+#define LIB_FIDL_CPP_INTERNAL_STUB_CONTROLLER_H_
+
+#include <memory>
+
+#include <lib/fidl/cpp/message.h>
+#include <lib/zx/channel.h>
+
+#include "lib/fidl/cpp/internal/message_handler.h"
+#include "lib/fidl/cpp/internal/message_reader.h"
+#include "lib/fidl/cpp/internal/stub.h"
+
+namespace fidl {
+namespace internal {
+class WeakStubController;
+
+// Controls the server endpoint of a FIDL channel.
+//
+// A |StubController| controls the protocol-specific "stub" object. Stub
+// objects are used on the server endpoint of a FIDL channel to decode messages
+// received over the channel and dispatch them to an implementation of the
+// protocol.
+class StubController : public MessageHandler {
+ public:
+  StubController();
+  ~StubController();
+
+  StubController(const StubController&) = delete;
+  StubController& operator=(const StubController&) = delete;
+
+  // The |MessageReader| that is listening for messages sent by the client.
+  MessageReader& reader() { return reader_; }
+  const MessageReader& reader() const { return reader_; }
+
+  // The protocol-specific object that decodes messages and dispatches them to
+  // an implementation of the protocol.
+  //
+  // The stub must be set to a non-null value before messages are read from the
+  // underlying channel. Typically, the caller will set a non-null stub before
+  // binding a channel to the |MessageReader|.
+  Stub* stub() const { return stub_; }
+  void set_stub(Stub* stub) { stub_ = stub; }
+
+  // Send a message over the channel.
+  //
+  // Returns an error if the message fails to encode properly or if the message
+  // cannot be written to the channel.
+  zx_status_t Send(const fidl_type_t* type, Message message);
+
+ private:
+  // Called by the |MessageReader| when a message arrives on the channel from
+  // the client.
+  //
+  // The message will be dispatched using the |stub()|. If the message expects a
+  // response, the |stub()| will also be given a |PendingResponse| object that
+  // can be used to send a reply to the message.
+  zx_status_t OnMessage(Message message) final;
+
+  // Causes the |StubController| to invalidate all outstanding weak pointers,
+  // preventing outstanding |PendingResponse| objects from sending messages on
+  // the channel that has gone away.
+  void OnChannelGone() final;
+
+  // Invalidate all outstanding weak pointers, preventing outstanding
+  // |PendingResponse| objects from sending messages.
+  void InvalidateWeakIfNeeded();
+
+  WeakStubController* weak_;
+  MessageReader reader_;
+  Stub* stub_;
+};
+
+}  // namespace internal
+}  // namespace fidl
+
+#endif  // LIB_FIDL_CPP_INTERNAL_STUB_CONTROLLER_H_
diff --git a/pkg/fidl_cpp/include/lib/fidl/cpp/internal/weak_stub_controller.h b/pkg/fidl_cpp/include/lib/fidl/cpp/internal/weak_stub_controller.h
new file mode 100644
index 0000000..cdfbb1d
--- /dev/null
+++ b/pkg/fidl_cpp/include/lib/fidl/cpp/internal/weak_stub_controller.h
@@ -0,0 +1,59 @@
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef LIB_FIDL_CPP_INTERNAL_WEAK_STUB_CONTROLLER_H_
+#define LIB_FIDL_CPP_INTERNAL_WEAK_STUB_CONTROLLER_H_
+
+#include <stdint.h>
+
+namespace fidl {
+namespace internal {
+class StubController;
+
+// A weak reference to a |StubController|.
+//
+// Used to link a |PendingResponse| object with a |StubController|. When the
+// |StubController| is destroyed (or unbound from the underling channel), the
+// weak reference is invalidated, preventing outstanding |PendingResponse|
+// objects from referencing the |StubController|.
+class WeakStubController {
+ public:
+  // Creates a weak reference to a |StubController|.
+  //
+  // The created |WeakStubController| has a reference count of one, which means
+  // the creator is responsible for calling |Release| exactly once.
+  explicit WeakStubController(StubController* controller);
+
+  // Increment the refernence count for this object.
+  //
+  // Each call to this method imposes a requirement to eventually call |Release|
+  // exactly once.
+  void AddRef();
+
+  // Decrements the reference count for this object.
+  //
+  // When the reference count reaches zero, the object is destroyed.
+  void Release();
+
+  // Break the connection between this object and the |StubController|.
+  //
+  // After calling this method, |controller()| will return nullptr.
+  void Invalidate();
+
+  // The |StubController| to which this weak reference refers.
+  //
+  // After the weak reference has been invalidated, this method returns nullptr.
+  StubController* controller() const { return controller_; }
+
+ private:
+  ~WeakStubController();
+
+  uint32_t ref_count_;  // starts at one
+  StubController* controller_;
+};
+
+}  // namespace internal
+}  // namespace fidl
+
+#endif  // LIB_FIDL_CPP_INTERNAL_WEAK_STUB_CONTROLLER_H_
diff --git a/pkg/fidl_cpp/include/lib/fidl/cpp/optional.h b/pkg/fidl_cpp/include/lib/fidl/cpp/optional.h
new file mode 100644
index 0000000..4dc6219
--- /dev/null
+++ b/pkg/fidl_cpp/include/lib/fidl/cpp/optional.h
@@ -0,0 +1,20 @@
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef LIB_FIDL_CPP_OPTIONAL_H_
+#define LIB_FIDL_CPP_OPTIONAL_H_
+
+#include <memory>
+#include <utility>
+
+namespace fidl {
+
+template <typename T>
+std::unique_ptr<T> MakeOptional(T value) {
+  return std::make_unique<T>(std::move(value));
+}
+
+}  // namespace fidl
+
+#endif  // LIB_FIDL_CPP_OPTIONAL_H_
diff --git a/pkg/fidl_cpp/include/lib/fidl/cpp/thread_safe_binding_set.h b/pkg/fidl_cpp/include/lib/fidl/cpp/thread_safe_binding_set.h
new file mode 100644
index 0000000..a3b572c
--- /dev/null
+++ b/pkg/fidl_cpp/include/lib/fidl/cpp/thread_safe_binding_set.h
@@ -0,0 +1,127 @@
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef LIB_FIDL_CPP_THREAD_SAFE_BINDING_SET_H_
+#define LIB_FIDL_CPP_THREAD_SAFE_BINDING_SET_H_
+
+#include <algorithm>
+#include <memory>
+#include <mutex>
+#include <utility>
+#include <vector>
+
+#include <lib/async/dispatcher.h>
+#include <zircon/compiler.h>
+
+#include "lib/fidl/cpp/binding.h"
+
+namespace fidl {
+
+// Manages a set of bindings to implemenations owned by the bound channels.
+//
+// The implementation pointer type of the binding is also parameterized,
+// allowing the use of smart pointer types such as |std::unique_ptr<>| to
+// reference the implementation.
+//
+// This class is thread-safe; bindings may be added or cleared from any thread.
+//
+// See also:
+//
+//  * |BindingSet|, which is the thread-hostile analog that offers more
+//    functionality.
+//  * |InterfacePtrSet|, which is the client analog of |BindingSet|.
+template <typename Interface, typename ImplPtr = Interface*>
+class ThreadSafeBindingSet {
+ public:
+  using Binding = ::fidl::Binding<Interface, ImplPtr>;
+  using StorageType = std::vector<std::unique_ptr<Binding>>;
+
+  ThreadSafeBindingSet() = default;
+
+  ThreadSafeBindingSet(const ThreadSafeBindingSet&) = delete;
+  ThreadSafeBindingSet& operator=(const ThreadSafeBindingSet&) = delete;
+
+  // Adds a binding to the set.
+  //
+  // The given |ImplPtr| is bound to the channel underlying the
+  // |InterfaceRequest|. The binding is removed (and the |~ImplPtr| called)
+  // when the created binding has an error (e.g., if the remote endpoint of
+  // the channel sends an invalid message).
+  //
+  // Whether this method takes ownership of |impl| depends on |ImplPtr|. If
+  // |ImplPtr| is a raw pointer, then this method does not take ownership of
+  // |impl|. If |ImplPtr| is a |unique_ptr|, then running |~ImplPtr| when the
+  // binding generates an error will delete |impl| because |~ImplPtr| is
+  // |~unique_ptr|, which deletes |impl|.
+  //
+  // The impl will use the given async_t (e.g., a message loop) in order to read
+  // messages from the channel and to monitor the channel for
+  // |ZX_CHANNEL_PEER_CLOSED|. It is not necessary to use the same async_t for
+  // each binding added.
+  void AddBinding(ImplPtr impl, InterfaceRequest<Interface> request,
+                  async_dispatcher_t* dispatcher) {
+    std::lock_guard<std::mutex> guard(lock_);
+    bindings_.push_back(std::make_unique<Binding>(
+        std::forward<ImplPtr>(impl), std::move(request), dispatcher));
+    auto* binding = bindings_.back().get();
+    // Set the connection error handler for the newly added Binding to be a
+    // function that will erase it from the vector.
+    binding->set_error_handler(
+        [binding, this](zx_status_t status) { this->RemoveOnError(binding); });
+  }
+
+  // Adds a binding to the set for the given implementation.
+  //
+  // Creates a channel for the binding and returns the client endpoint of
+  // the channel as an |InterfaceHandle|. If |AddBinding| fails to create the
+  // underlying channel, the returned |InterfaceHandle| will return false from
+  // |is_valid()|.
+  //
+  // The given |ImplPtr| is bound to the newly created channel. The binding is
+  // removed (and the |~ImplPtr| called) when the created binding has an error
+  // (e.g., if the remote endpoint of the channel sends an invalid message).
+  //
+  // Whether this method takes ownership of |impl| depends on |ImplPtr|. If
+  // |ImplPtr| is a raw pointer, then this method does not take ownership of
+  // |impl|. If |ImplPtr| is a |unique_ptr|, then running |~ImplPtr| when the
+  // binding generates an error will delete |impl| because |~ImplPtr| is
+  // |~unique_ptr|, which deletes |impl|.
+  InterfaceHandle<Interface> AddBinding(ImplPtr impl,
+                                        async_dispatcher_t* dispatcher) {
+    InterfaceHandle<Interface> handle;
+    InterfaceRequest<Interface> request = handle.NewRequest();
+    if (!request)
+      return nullptr;
+    AddBinding(std::forward<ImplPtr>(impl), std::move(request), dispatcher);
+    return handle;
+  }
+
+  // Removes all the bindings from the set.
+  //
+  // Closes all the channels associated with this |BindingSet|.
+  void CloseAll() {
+    std::lock_guard<std::mutex> guard(lock_);
+    bindings_.clear();
+  }
+
+ private:
+  // Called when a binding has an error to remove the binding from the set.
+  void RemoveOnError(Binding* binding) {
+    std::lock_guard<std::mutex> guard(lock_);
+    auto it = std::find_if(bindings_.begin(), bindings_.end(),
+                           [binding](const std::unique_ptr<Binding>& b) {
+                             return b.get() == binding;
+                           });
+    ZX_DEBUG_ASSERT(it != bindings_.end());
+    (*it)->set_error_handler(nullptr);
+    bindings_.erase(it);
+  }
+
+  std::mutex lock_;
+  StorageType bindings_ __TA_GUARDED(lock_);
+};
+
+}  // namespace fidl
+
+#endif  // LIB_FIDL_CPP_THREAD_SAFE_BINDING_SET_H_
diff --git a/pkg/fidl_cpp/internal/message_handler.cc b/pkg/fidl_cpp/internal/message_handler.cc
new file mode 100644
index 0000000..fbcaa5a
--- /dev/null
+++ b/pkg/fidl_cpp/internal/message_handler.cc
@@ -0,0 +1,15 @@
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "lib/fidl/cpp/internal/message_handler.h"
+
+namespace fidl {
+namespace internal {
+
+MessageHandler::~MessageHandler() = default;
+
+void MessageHandler::OnChannelGone() {}
+
+}  // namespace internal
+}  // namespace fidl
diff --git a/pkg/fidl_cpp/internal/message_reader.cc b/pkg/fidl_cpp/internal/message_reader.cc
new file mode 100644
index 0000000..e4331f7
--- /dev/null
+++ b/pkg/fidl_cpp/internal/message_reader.cc
@@ -0,0 +1,268 @@
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "lib/fidl/cpp/internal/message_reader.h"
+
+#include <lib/async/default.h>
+#include <lib/fidl/cpp/message_buffer.h>
+#include <lib/fidl/epitaph.h>
+#include <zircon/assert.h>
+
+namespace fidl {
+namespace internal {
+namespace {
+
+constexpr zx_signals_t kSignals = ZX_CHANNEL_READABLE | ZX_CHANNEL_PEER_CLOSED;
+
+// |Canary| is a stack-allocated object that observes when a |MessageReader| is
+// destroyed or unbound from the current channel.
+//
+// Because |WaitAndDispatchOneMessageUntil| can be called re-entrantly, we can
+// be in a state where there are N nested calls to |ReadAndDispatchMessage| on
+// the stack. While dispatching any of those messages, the client can destroy
+// the |MessageReader| or unbind it from the current channel. When that happens
+// we need to stop reading messages from the channel and unwind the stack
+// safely.
+//
+// The |Canary| works by storing a pointer to its |should_stop_| field in the
+// |MessageReader|.  Upon destruction or unbinding, the |MessageReader| writes
+// |true| into |should_stop_|. When we unwind the stack, the |Canary| forwards
+// that value to the next |Canary| on the stack.
+class Canary {
+ public:
+  explicit Canary(bool** should_stop_slot)
+      : should_stop_slot_(should_stop_slot),
+        previous_should_stop_(*should_stop_slot_),
+        should_stop_(false) {
+    *should_stop_slot_ = &should_stop_;
+  }
+
+  ~Canary() {
+    if (should_stop_) {
+      // If we should stop, we need to propagate that information to the
+      // |Canary| higher up the stack, if any. We also cannot touch
+      // |*should_stop_slot_| because the |MessageReader| might have been
+      // destroyed (or bound to another channel).
+      if (previous_should_stop_)
+        *previous_should_stop_ = should_stop_;
+    } else {
+      // Otherwise, the |MessageReader| was not destroyed and is still bound to
+      // the same channel. We need to restore the previous |should_stop_|
+      // pointer so that a |Canary| further up the stack can still be informed
+      // about whether to stop.
+      *should_stop_slot_ = previous_should_stop_;
+    }
+  }
+
+  // Whether the |ReadAndDispatchMessage| that created the |Canary| should stop
+  // after dispatching the current message.
+  bool should_stop() const { return should_stop_; }
+
+ private:
+  bool** should_stop_slot_;
+  bool* previous_should_stop_;
+  bool should_stop_;
+};
+
+}  // namespace
+
+static_assert(std::is_standard_layout<MessageReader>::value,
+              "We need offsetof to work");
+
+MessageReader::MessageReader(MessageHandler* message_handler)
+    : wait_{{ASYNC_STATE_INIT},
+            &MessageReader::CallHandler,
+            ZX_HANDLE_INVALID,
+            kSignals},
+      dispatcher_(nullptr),
+      should_stop_(nullptr),
+      message_handler_(message_handler),
+      error_handler_(nullptr) {}
+
+MessageReader::~MessageReader() {
+  Stop();
+  if (dispatcher_)
+    async_cancel_wait(dispatcher_, &wait_);
+}
+
+zx_status_t MessageReader::Bind(zx::channel channel,
+                                async_dispatcher_t* dispatcher) {
+  if (is_bound())
+    Unbind();
+  if (!channel)
+    return ZX_OK;
+  channel_ = std::move(channel);
+  if (dispatcher) {
+    dispatcher_ = dispatcher;
+  } else {
+    dispatcher_ = async_get_default_dispatcher();
+  }
+  ZX_ASSERT_MSG(dispatcher_ != nullptr,
+                "either |dispatcher| must be non-null, or "
+                "|async_get_default_dispatcher| must "
+                "be configured to return a non-null value");
+  wait_.object = channel_.get();
+  zx_status_t status = async_begin_wait(dispatcher_, &wait_);
+  if (status != ZX_OK)
+    Unbind();
+  return status;
+}
+
+zx::channel MessageReader::Unbind() {
+  if (!is_bound())
+    return zx::channel();
+  Stop();
+  async_cancel_wait(dispatcher_, &wait_);
+  wait_.object = ZX_HANDLE_INVALID;
+  dispatcher_ = nullptr;
+  zx::channel channel = std::move(channel_);
+  if (message_handler_)
+    message_handler_->OnChannelGone();
+  return channel;
+}
+
+void MessageReader::Reset() {
+  Unbind();
+  error_handler_ = nullptr;
+}
+
+zx_status_t MessageReader::TakeChannelAndErrorHandlerFrom(
+    MessageReader* other) {
+  zx_status_t status = Bind(other->Unbind(), other->dispatcher_);
+  if (status != ZX_OK)
+    return status;
+  error_handler_ = std::move(other->error_handler_);
+  return ZX_OK;
+}
+
+zx_status_t MessageReader::WaitAndDispatchOneMessageUntil(zx::time deadline) {
+  if (!is_bound())
+    return ZX_ERR_BAD_STATE;
+  zx_signals_t pending = ZX_SIGNAL_NONE;
+  zx_status_t status = channel_.wait_one(kSignals, deadline, &pending);
+  if (status == ZX_ERR_TIMED_OUT)
+    return status;
+  if (status != ZX_OK) {
+    NotifyError(status);
+    return status;
+  }
+
+  if (pending & ZX_CHANNEL_READABLE) {
+    MessageBuffer buffer;
+    return ReadAndDispatchMessage(&buffer);
+  }
+
+  ZX_DEBUG_ASSERT(pending & ZX_CHANNEL_PEER_CLOSED);
+  NotifyError(ZX_ERR_PEER_CLOSED);
+  return ZX_ERR_PEER_CLOSED;
+}
+
+void MessageReader::CallHandler(async_dispatcher_t* dispatcher,
+                                async_wait_t* wait, zx_status_t status,
+                                const zx_packet_signal_t* signal) {
+  static_assert(offsetof(MessageReader, wait_) == 0,
+                "The wait must be the first member for this cast to be valid.");
+  reinterpret_cast<MessageReader*>(wait)->OnHandleReady(dispatcher, status,
+                                                        signal);
+}
+
+void MessageReader::OnHandleReady(async_dispatcher_t* dispatcher,
+                                  zx_status_t status,
+                                  const zx_packet_signal_t* signal) {
+  if (status != ZX_OK) {
+    NotifyError(status);
+    return;
+  }
+
+  if (signal->observed & ZX_CHANNEL_READABLE) {
+    MessageBuffer buffer;
+    for (uint64_t i = 0; i < signal->count; i++) {
+      status = ReadAndDispatchMessage(&buffer);
+      // If ReadAndDispatchMessage returns ZX_ERR_STOP, that means the message
+      // handler has destroyed this object and we need to unwind without
+      // touching |this|.
+      if (status == ZX_ERR_SHOULD_WAIT)
+        break;
+      if (status != ZX_OK)
+        return;
+    }
+    status = async_begin_wait(dispatcher, &wait_);
+    if (status != ZX_OK) {
+      NotifyError(status);
+    }
+    return;
+  }
+
+  ZX_DEBUG_ASSERT(signal->observed & ZX_CHANNEL_PEER_CLOSED);
+  // Notice that we don't notify an error until we've drained all the messages
+  // out of the channel.
+  NotifyError(ZX_ERR_PEER_CLOSED);
+}
+
+zx_status_t MessageReader::ReadAndDispatchMessage(MessageBuffer* buffer) {
+  Message message = buffer->CreateEmptyMessage();
+  zx_status_t status = message.Read(channel_.get(), 0);
+  if (status == ZX_ERR_SHOULD_WAIT)
+    return status;
+  if (status != ZX_OK) {
+    NotifyError(status);
+    return status;
+  }
+
+  if (message.has_header() && message.ordinal() == FIDL_EPITAPH_ORDINAL) {
+    // This indicates the message is an epitaph, and that any epitaph-friendly
+    // error handlers should be invoked.  Note the epitaph error is stored in
+    // the header's reserved word.
+
+    // TODO(FIDL-322): Use a different error code to distinguish remote encoding
+    // errors from local ones.
+    if (message.bytes().actual() != sizeof(fidl_epitaph_t)) {
+      NotifyError(ZX_ERR_INVALID_ARGS);
+      return ZX_ERR_INVALID_ARGS;
+    }
+    fidl_epitaph_t* epitaph = message.GetBytesAs<fidl_epitaph_t>();
+    NotifyError(epitaph->hdr.reserved0);
+    return ZX_ERR_PEER_CLOSED;
+  }
+
+  if (!message_handler_)
+    return ZX_OK;
+  Canary canary(&should_stop_);
+  status = message_handler_->OnMessage(std::move(message));
+  if (canary.should_stop())
+    return ZX_ERR_STOP;
+  if (status != ZX_OK)
+    NotifyError(status);
+  return status;
+}
+
+zx_status_t MessageReader::Close(zx_status_t epitaph_value) {
+  if (!is_bound()) {
+    return ZX_ERR_BAD_STATE;
+  }
+
+  zx_status_t status = fidl_epitaph_write(channel_.get(), epitaph_value);
+  if (status != ZX_OK) {
+    return status;
+  }
+  Unbind();
+  return ZX_OK;
+}
+
+void MessageReader::NotifyError(zx_status_t epitaph_value) {
+  Unbind();
+  if (error_handler_) {
+    error_handler_(epitaph_value);
+  }
+}
+
+void MessageReader::Stop() {
+  if (should_stop_) {
+    *should_stop_ = true;
+    should_stop_ = nullptr;
+  }
+}
+
+}  // namespace internal
+}  // namespace fidl
diff --git a/pkg/fidl_cpp/internal/pending_response.cc b/pkg/fidl_cpp/internal/pending_response.cc
new file mode 100644
index 0000000..3ac41ae
--- /dev/null
+++ b/pkg/fidl_cpp/internal/pending_response.cc
@@ -0,0 +1,77 @@
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "lib/fidl/cpp/internal/pending_response.h"
+
+#include "lib/fidl/cpp/internal/logging.h"
+#include "lib/fidl/cpp/internal/stub_controller.h"
+#include "lib/fidl/cpp/internal/weak_stub_controller.h"
+
+namespace fidl {
+namespace internal {
+
+PendingResponse::PendingResponse() : txid_(0), weak_controller_(nullptr) {}
+
+PendingResponse::PendingResponse(zx_txid_t txid,
+                                 WeakStubController* weak_controller)
+    : txid_(txid), weak_controller_(weak_controller) {
+  if (weak_controller_)
+    weak_controller_->AddRef();
+}
+
+PendingResponse::~PendingResponse() {
+  if (weak_controller_)
+    weak_controller_->Release();
+}
+
+PendingResponse::PendingResponse(const PendingResponse& other)
+    : PendingResponse(other.txid_, other.weak_controller_) {}
+
+PendingResponse& PendingResponse::operator=(const PendingResponse& other) {
+  if (this == &other)
+    return *this;
+  txid_ = other.txid_;
+  if (weak_controller_)
+    weak_controller_->Release();
+  weak_controller_ = other.weak_controller_;
+  if (weak_controller_)
+    weak_controller_->AddRef();
+  return *this;
+}
+
+PendingResponse::PendingResponse(PendingResponse&& other)
+    : txid_(other.txid_), weak_controller_(other.weak_controller_) {
+  other.weak_controller_ = nullptr;
+}
+
+PendingResponse& PendingResponse::operator=(PendingResponse&& other) {
+  if (this == &other)
+    return *this;
+  txid_ = other.txid_;
+  if (weak_controller_)
+    weak_controller_->Release();
+  weak_controller_ = other.weak_controller_;
+  other.weak_controller_ = nullptr;
+  return *this;
+}
+
+zx_status_t PendingResponse::Send(const fidl_type_t* type, Message message) {
+  if (!weak_controller_)
+    return ZX_ERR_BAD_STATE;
+  StubController* controller = weak_controller_->controller();
+  if (!controller)
+    return ZX_ERR_BAD_STATE;
+  message.set_txid(txid_);
+  const char* error_msg = nullptr;
+  zx_status_t status = message.Validate(type, &error_msg);
+  if (status != ZX_OK) {
+    FIDL_REPORT_ENCODING_ERROR(message, type, error_msg);
+    return status;
+  }
+  zx_handle_t channel = controller->reader().channel().get();
+  return message.Write(channel, 0);
+}
+
+}  // namespace internal
+}  // namespace fidl
diff --git a/pkg/fidl_cpp/internal/proxy.cc b/pkg/fidl_cpp/internal/proxy.cc
new file mode 100644
index 0000000..412aff7
--- /dev/null
+++ b/pkg/fidl_cpp/internal/proxy.cc
@@ -0,0 +1,13 @@
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "lib/fidl/cpp/internal/proxy.h"
+
+namespace fidl {
+namespace internal {
+
+Proxy::~Proxy() = default;
+
+}  // namespace internal
+}  // namespace fidl
diff --git a/pkg/fidl_cpp/internal/proxy_controller.cc b/pkg/fidl_cpp/internal/proxy_controller.cc
new file mode 100644
index 0000000..bec764c
--- /dev/null
+++ b/pkg/fidl_cpp/internal/proxy_controller.cc
@@ -0,0 +1,97 @@
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "lib/fidl/cpp/internal/proxy_controller.h"
+
+#include <utility>
+
+#include "lib/fidl/cpp/internal/logging.h"
+
+namespace fidl {
+namespace internal {
+namespace {
+
+constexpr uint32_t kUserspaceTxidMask = 0x7FFFFFFF;
+
+}  // namespace
+
+ProxyController::ProxyController() : reader_(this), next_txid_(1) {}
+
+ProxyController::~ProxyController() = default;
+
+ProxyController::ProxyController(ProxyController&& other)
+    : reader_(this),
+      handlers_(std::move(other.handlers_)),
+      next_txid_(other.next_txid_) {
+  reader_.TakeChannelAndErrorHandlerFrom(&other.reader());
+  other.Reset();
+}
+
+ProxyController& ProxyController::operator=(ProxyController&& other) {
+  if (this != &other) {
+    reader_.TakeChannelAndErrorHandlerFrom(&other.reader());
+    handlers_ = std::move(other.handlers_);
+    next_txid_ = other.next_txid_;
+    other.Reset();
+  }
+  return *this;
+}
+
+zx_status_t ProxyController::Send(
+    const fidl_type_t* type, Message message,
+    std::unique_ptr<MessageHandler> response_handler) {
+  zx_txid_t txid = 0;
+  if (response_handler) {
+    txid = next_txid_++ & kUserspaceTxidMask;
+    while (!txid || handlers_.find(txid) != handlers_.end())
+      txid = next_txid_++ & kUserspaceTxidMask;
+    message.set_txid(txid);
+  }
+  const char* error_msg = nullptr;
+  zx_status_t status = message.Validate(type, &error_msg);
+  if (status != ZX_OK) {
+    FIDL_REPORT_ENCODING_ERROR(message, type, error_msg);
+    return status;
+  }
+  status = message.Write(reader_.channel().get(), 0);
+  if (status != ZX_OK) {
+    FIDL_REPORT_CHANNEL_WRITING_ERROR(message, type, status);
+    return status;
+  }
+  if (response_handler)
+    handlers_.emplace(txid, std::move(response_handler));
+  return ZX_OK;
+}
+
+void ProxyController::Reset() {
+  reader_.Reset();
+  ClearPendingHandlers();
+}
+
+zx_status_t ProxyController::OnMessage(Message message) {
+  if (!message.has_header())
+    return ZX_ERR_INVALID_ARGS;
+  zx_txid_t txid = message.txid();
+  if (!txid) {
+    if (!proxy_)
+      return ZX_ERR_NOT_SUPPORTED;
+    return proxy_->Dispatch_(std::move(message));
+  }
+  auto it = handlers_.find(txid);
+  if (it == handlers_.end())
+    return ZX_ERR_NOT_FOUND;
+  std::unique_ptr<MessageHandler> handler = std::move(it->second);
+  handlers_.erase(it);
+  return handler->OnMessage(std::move(message));
+}
+
+void ProxyController::OnChannelGone() { ClearPendingHandlers(); }
+
+void ProxyController::ClearPendingHandlers() {
+  handlers_.clear();
+  next_txid_ = 1;
+}
+
+}  // namespace internal
+}  // namespace fidl
diff --git a/pkg/fidl_cpp/internal/stub.cc b/pkg/fidl_cpp/internal/stub.cc
new file mode 100644
index 0000000..0ddec10
--- /dev/null
+++ b/pkg/fidl_cpp/internal/stub.cc
@@ -0,0 +1,13 @@
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "lib/fidl/cpp/internal/stub.h"
+
+namespace fidl {
+namespace internal {
+
+Stub::~Stub() = default;
+
+}  // namespace internal
+}  // namespace fidl
diff --git a/pkg/fidl_cpp/internal/stub_controller.cc b/pkg/fidl_cpp/internal/stub_controller.cc
new file mode 100644
index 0000000..2244229
--- /dev/null
+++ b/pkg/fidl_cpp/internal/stub_controller.cc
@@ -0,0 +1,52 @@
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "lib/fidl/cpp/internal/stub_controller.h"
+
+#include "lib/fidl/cpp/internal/logging.h"
+#include "lib/fidl/cpp/internal/pending_response.h"
+#include "lib/fidl/cpp/internal/weak_stub_controller.h"
+
+namespace fidl {
+namespace internal {
+
+StubController::StubController() : weak_(nullptr), reader_(this) {}
+
+StubController::~StubController() { InvalidateWeakIfNeeded(); }
+
+zx_status_t StubController::Send(const fidl_type_t* type, Message message) {
+  const char* error_msg = nullptr;
+  zx_status_t status = message.Validate(type, &error_msg);
+  if (status != ZX_OK) {
+    FIDL_REPORT_ENCODING_ERROR(message, type, error_msg);
+    return status;
+  }
+  return message.Write(reader_.channel().get(), 0);
+}
+
+zx_status_t StubController::OnMessage(Message message) {
+  if (!message.has_header())
+    return ZX_ERR_INVALID_ARGS;
+  zx_txid_t txid = message.txid();
+  WeakStubController* weak = nullptr;
+  if (txid) {
+    if (!weak_)
+      weak_ = new WeakStubController(this);
+    weak = weak_;
+  }
+  return stub_->Dispatch_(std::move(message), PendingResponse(txid, weak));
+}
+
+void StubController::OnChannelGone() { InvalidateWeakIfNeeded(); }
+
+void StubController::InvalidateWeakIfNeeded() {
+  if (!weak_)
+    return;
+  weak_->Invalidate();
+  weak_->Release();
+  weak_ = nullptr;
+}
+
+}  // namespace internal
+}  // namespace fidl
diff --git a/pkg/fidl_cpp/internal/weak_stub_controller.cc b/pkg/fidl_cpp/internal/weak_stub_controller.cc
new file mode 100644
index 0000000..7693ef7
--- /dev/null
+++ b/pkg/fidl_cpp/internal/weak_stub_controller.cc
@@ -0,0 +1,25 @@
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "lib/fidl/cpp/internal/weak_stub_controller.h"
+
+namespace fidl {
+namespace internal {
+
+WeakStubController::WeakStubController(StubController* controller)
+    : ref_count_(1u), controller_(controller) {}
+
+WeakStubController::~WeakStubController() = default;
+
+void WeakStubController::AddRef() { ++ref_count_; }
+
+void WeakStubController::Release() {
+  if (--ref_count_ == 0)
+    delete this;
+}
+
+void WeakStubController::Invalidate() { controller_ = nullptr; }
+
+}  // namespace internal
+}  // namespace fidl
diff --git a/pkg/fidl_cpp/meta.json b/pkg/fidl_cpp/meta.json
new file mode 100644
index 0000000..37f840f
--- /dev/null
+++ b/pkg/fidl_cpp/meta.json
@@ -0,0 +1,45 @@
+{
+  "deps": [
+    "fidl_cpp_sync", 
+    "async", 
+    "async-default", 
+    "fidl", 
+    "fidl-async", 
+    "fit", 
+    "zx"
+  ], 
+  "fidl_deps": [], 
+  "headers": [
+    "pkg/fidl_cpp/include/lib/fidl/cpp/binding.h", 
+    "pkg/fidl_cpp/include/lib/fidl/cpp/binding_set.h", 
+    "pkg/fidl_cpp/include/lib/fidl/cpp/enum.h", 
+    "pkg/fidl_cpp/include/lib/fidl/cpp/interface_ptr.h", 
+    "pkg/fidl_cpp/include/lib/fidl/cpp/interface_ptr_set.h", 
+    "pkg/fidl_cpp/include/lib/fidl/cpp/internal/header.h", 
+    "pkg/fidl_cpp/include/lib/fidl/cpp/internal/implementation.h", 
+    "pkg/fidl_cpp/include/lib/fidl/cpp/internal/message_handler.h", 
+    "pkg/fidl_cpp/include/lib/fidl/cpp/internal/message_reader.h", 
+    "pkg/fidl_cpp/include/lib/fidl/cpp/internal/pending_response.h", 
+    "pkg/fidl_cpp/include/lib/fidl/cpp/internal/proxy.h", 
+    "pkg/fidl_cpp/include/lib/fidl/cpp/internal/proxy_controller.h", 
+    "pkg/fidl_cpp/include/lib/fidl/cpp/internal/stub.h", 
+    "pkg/fidl_cpp/include/lib/fidl/cpp/internal/stub_controller.h", 
+    "pkg/fidl_cpp/include/lib/fidl/cpp/internal/weak_stub_controller.h", 
+    "pkg/fidl_cpp/include/lib/fidl/cpp/optional.h", 
+    "pkg/fidl_cpp/include/lib/fidl/cpp/thread_safe_binding_set.h"
+  ], 
+  "include_dir": "pkg/fidl_cpp/include", 
+  "name": "fidl_cpp", 
+  "root": "pkg/fidl_cpp", 
+  "sources": [
+    "pkg/fidl_cpp/internal/message_handler.cc", 
+    "pkg/fidl_cpp/internal/message_reader.cc", 
+    "pkg/fidl_cpp/internal/pending_response.cc", 
+    "pkg/fidl_cpp/internal/proxy.cc", 
+    "pkg/fidl_cpp/internal/proxy_controller.cc", 
+    "pkg/fidl_cpp/internal/stub.cc", 
+    "pkg/fidl_cpp/internal/stub_controller.cc", 
+    "pkg/fidl_cpp/internal/weak_stub_controller.cc"
+  ], 
+  "type": "cc_source_library"
+}
\ No newline at end of file
diff --git a/pkg/fidl_cpp_base/clone.cc b/pkg/fidl_cpp_base/clone.cc
new file mode 100644
index 0000000..9b4e80a
--- /dev/null
+++ b/pkg/fidl_cpp_base/clone.cc
@@ -0,0 +1,18 @@
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "lib/fidl/cpp/clone.h"
+
+namespace fidl {
+
+zx_status_t Clone(const StringPtr& value, StringPtr* result) {
+  if (!value) {
+    *result = StringPtr();
+  } else {
+    result->reset(*value);
+  }
+  return ZX_OK;
+}
+
+}  // namespace fidl
diff --git a/pkg/fidl_cpp_base/coding_traits.cc b/pkg/fidl_cpp_base/coding_traits.cc
new file mode 100644
index 0000000..e66d8bd
--- /dev/null
+++ b/pkg/fidl_cpp_base/coding_traits.cc
@@ -0,0 +1,21 @@
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "lib/fidl/cpp/coding_traits.h"
+
+namespace fidl {
+
+void EncodeNullVector(Encoder* encoder, size_t offset) {
+  fidl_vector_t* vector = encoder->GetPtr<fidl_vector_t>(offset);
+  vector->count = 0u;
+  vector->data = reinterpret_cast<void*>(FIDL_ALLOC_ABSENT);
+}
+
+void EncodeVectorPointer(Encoder* encoder, size_t count, size_t offset) {
+  fidl_vector_t* vector = encoder->GetPtr<fidl_vector_t>(offset);
+  vector->count = count;
+  vector->data = reinterpret_cast<void*>(FIDL_ALLOC_PRESENT);
+}
+
+}  // namespace fidl
diff --git a/pkg/fidl_cpp_base/decoder.cc b/pkg/fidl_cpp_base/decoder.cc
new file mode 100644
index 0000000..bec4ee0
--- /dev/null
+++ b/pkg/fidl_cpp_base/decoder.cc
@@ -0,0 +1,38 @@
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "lib/fidl/cpp/decoder.h"
+
+#include <utility>
+
+namespace fidl {
+
+Decoder::Decoder(Message message) : message_(std::move(message)) {}
+
+Decoder::~Decoder() = default;
+
+size_t Decoder::GetOffset(void* ptr) {
+  return GetOffset(reinterpret_cast<uintptr_t>(ptr));
+}
+
+size_t Decoder::GetOffset(uintptr_t ptr) {
+  // The |ptr| value comes from the message buffer, which we've already
+  // validated. That means it should coorespond to a valid offset within the
+  // message.
+  return ptr - reinterpret_cast<uintptr_t>(message_.bytes().data());
+}
+
+#ifdef __Fuchsia__
+void Decoder::DecodeHandle(zx::object_base* value, size_t offset) {
+  zx_handle_t* handle = GetPtr<zx_handle_t>(offset);
+  value->reset(*handle);
+  *handle = ZX_HANDLE_INVALID;
+}
+#endif
+
+uint8_t* Decoder::InternalGetPtr(size_t offset) {
+  return message_.bytes().data() + offset;
+}
+
+}  // namespace fidl
diff --git a/pkg/fidl_cpp_base/encoder.cc b/pkg/fidl_cpp_base/encoder.cc
new file mode 100644
index 0000000..01ffb44
--- /dev/null
+++ b/pkg/fidl_cpp_base/encoder.cc
@@ -0,0 +1,60 @@
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "lib/fidl/cpp/encoder.h"
+
+#include <zircon/assert.h>
+#include <zircon/fidl.h>
+
+namespace fidl {
+namespace {
+
+size_t Align(size_t size) {
+  constexpr size_t alignment_mask = FIDL_ALIGNMENT - 1;
+  return (size + alignment_mask) & ~alignment_mask;
+}
+
+}  // namespace
+
+Encoder::Encoder(uint32_t ordinal) { EncodeMessageHeader(ordinal); }
+
+Encoder::~Encoder() = default;
+
+size_t Encoder::Alloc(size_t size) {
+  size_t offset = bytes_.size();
+  size_t new_size = bytes_.size() + Align(size);
+  ZX_ASSERT(new_size >= offset);
+  bytes_.resize(new_size);
+  return offset;
+}
+
+#ifdef __Fuchsia__
+void Encoder::EncodeHandle(zx::object_base* value, size_t offset) {
+  if (value->is_valid()) {
+    *GetPtr<zx_handle_t>(offset) = FIDL_HANDLE_PRESENT;
+    handles_.push_back(value->release());
+  } else {
+    *GetPtr<zx_handle_t>(offset) = FIDL_HANDLE_ABSENT;
+  }
+}
+#endif
+
+Message Encoder::GetMessage() {
+  return Message(BytePart(bytes_.data(), bytes_.size(), bytes_.size()),
+                 HandlePart(handles_.data(), handles_.size(), handles_.size()));
+}
+
+void Encoder::Reset(uint32_t ordinal) {
+  bytes_.clear();
+  handles_.clear();
+  EncodeMessageHeader(ordinal);
+}
+
+void Encoder::EncodeMessageHeader(uint32_t ordinal) {
+  size_t offset = Alloc(sizeof(fidl_message_header_t));
+  fidl_message_header_t* header = GetPtr<fidl_message_header_t>(offset);
+  header->ordinal = ordinal;
+}
+
+}  // namespace fidl
diff --git a/pkg/fidl_cpp_base/include/lib/fidl/cpp/array.h b/pkg/fidl_cpp_base/include/lib/fidl/cpp/array.h
new file mode 100644
index 0000000..aeb35e6
--- /dev/null
+++ b/pkg/fidl_cpp_base/include/lib/fidl/cpp/array.h
@@ -0,0 +1,98 @@
+// Copyright 2017 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef LIB_FIDL_CPP_ARRAY_H_
+#define LIB_FIDL_CPP_ARRAY_H_
+
+#include <stddef.h>
+#include <string.h>
+
+#include <lib/fidl/cpp/comparison.h>
+
+namespace fidl {
+
+template <typename T, size_t N>
+class Array {
+ public:
+  Array() { memset(data_, 0, sizeof(data_)); }
+
+  constexpr size_t size() const { return N; }
+
+  // TODO(FIDL-245) Remove this overload.
+  constexpr size_t count() const { return N; }
+
+  const T* data() const { return data_; }
+  T* data() { return data_; }
+
+  // TODO(FIDL-245) Remove this overload.
+  T* mutable_data() { return data_; }
+
+  const T& at(size_t offset) const { return data()[offset]; }
+  T& at(size_t offset) { return mutable_data()[offset]; }
+
+  const T& operator[](size_t offset) const { return at(offset); }
+  T& operator[](size_t offset) { return at(offset); }
+
+  T* begin() { return mutable_data(); }
+  const T* begin() const { return data(); }
+  const T* cbegin() const { return data(); }
+
+  T* end() { return mutable_data() + count(); }
+  const T* end() const { return data() + count(); }
+  const T* cend() const { return data() + count(); }
+
+ private:
+  static_assert(N > 0, "fid::Array cannot have zero elements.");
+
+  T data_[N];
+};
+
+template <typename T, size_t N>
+bool operator==(const Array<T, N>& lhs, const Array<T, N>& rhs) {
+  for (size_t i = 0; i < N; ++i) {
+    if (!Equals(lhs[i], rhs[i])) {
+      return false;
+    }
+  }
+  return true;
+}
+
+template <typename T, size_t N>
+bool operator!=(const Array<T, N>& lhs, const Array<T, N>& rhs) {
+  return !(lhs == rhs);
+}
+
+template <typename T, size_t N>
+bool operator<(const Array<T, N>& lhs, const Array<T, N>& rhs) {
+  for (size_t i = 0; i < N; i++) {
+    if (lhs[i] != rhs[i]) {
+      return lhs[i] < rhs[i];
+    }
+  }
+  return false;
+}
+
+template <typename T, size_t N>
+bool operator>(const Array<T, N>& lhs, const Array<T, N>& rhs) {
+  for (size_t i = 0; i < N; i++) {
+    if (lhs[i] != rhs[i]) {
+      return lhs[i] > rhs[i];
+    }
+  }
+  return false;
+}
+
+template <typename T, size_t N>
+bool operator<=(const Array<T, N>& lhs, const Array<T, N>& rhs) {
+  return !(lhs > rhs);
+}
+
+template <typename T, size_t N>
+bool operator>=(const Array<T, N>& lhs, const Array<T, N>& rhs) {
+  return !(lhs < rhs);
+}
+
+}  // namespace fidl
+
+#endif  // LIB_FIDL_CPP_ARRAY_H_
diff --git a/pkg/fidl_cpp_base/include/lib/fidl/cpp/clone.h b/pkg/fidl_cpp_base/include/lib/fidl/cpp/clone.h
new file mode 100644
index 0000000..8c1c108
--- /dev/null
+++ b/pkg/fidl_cpp_base/include/lib/fidl/cpp/clone.h
@@ -0,0 +1,141 @@
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef LIB_FIDL_CPP_CLONE_H_
+#define LIB_FIDL_CPP_CLONE_H_
+
+#include <lib/fidl/cpp/array.h>
+#include <zircon/assert.h>
+#include <memory>
+#include "lib/fidl/cpp/string.h"
+#include "lib/fidl/cpp/traits.h"
+#include "lib/fidl/cpp/vector.h"
+
+namespace fidl {
+
+#ifdef __Fuchsia__
+namespace internal {
+
+template <typename T>
+inline typename std::enable_if<zx::object_traits<T>::supports_duplication,
+                               zx_status_t>::type
+CloneKernelObject(const zx::object<T>& object, zx::object<T>* result) {
+  return object.duplicate(ZX_RIGHT_SAME_RIGHTS, result);
+}
+
+template <typename T>
+inline typename std::enable_if<!zx::object_traits<T>::supports_duplication,
+                               zx_status_t>::type
+CloneKernelObject(const zx::object<T>& object, zx::object<T>* result) {
+  return ZX_ERR_ACCESS_DENIED;
+}
+
+}  // namespace internal
+#endif  // __Fuchsia__
+
+// Deep copies the contents of |value| into |result|.
+// This operation also attempts to duplicate any handles the value contains.
+//
+// Returns an error if the value could not be cloned, perhaps because a
+// handle was not duplicable.
+//
+// There are many overloads of this function with the following signature:
+//   zx_status_t Clone(const T& value, T* result);
+template <typename T>
+inline typename std::enable_if<IsPrimitive<T>::value, zx_status_t>::type Clone(
+    const T& value, T* result) {
+  *result = value;
+  return ZX_OK;
+}
+
+template <typename T>
+inline
+#ifdef __Fuchsia__
+    typename std::enable_if<!IsPrimitive<T>::value &&
+                                !std::is_base_of<zx::object_base, T>::value,
+                            zx_status_t>::type
+#else   // __Fuchsia__
+    typename std::enable_if<!IsPrimitive<T>::value, zx_status_t>::type
+#endif  // __Fuchsia__
+    Clone(const T& value, T* result) {
+  return value.Clone(result);
+}
+
+#ifdef __Fuchsia__
+template <typename T>
+zx_status_t Clone(const zx::object<T>& value, zx::object<T>* result) {
+  if (!value) {
+    result->reset();
+    return ZX_OK;
+  }
+  return internal::CloneKernelObject(value, result);
+}
+#endif  // __Fuchsia__
+
+template <typename T>
+inline zx_status_t Clone(const std::unique_ptr<T>& value,
+                         std::unique_ptr<T>* result) {
+  if (!value) {
+    result->reset();
+    return ZX_OK;
+  }
+  *result = std::make_unique<T>();
+  return Clone(*value, result->get());
+}
+
+template <typename T>
+inline typename std::enable_if<!IsPrimitive<T>::value, zx_status_t>::type Clone(
+    const VectorPtr<T>& value, VectorPtr<T>* result) {
+  if (!value) {
+    *result = VectorPtr<T>();
+    return ZX_OK;
+  }
+  result->resize(value->size());
+  for (size_t i = 0; i < value->size(); ++i) {
+    zx_status_t status = Clone(value->at(i), &(*result)->at(i));
+    if (status != ZX_OK)
+      return status;
+  }
+  return ZX_OK;
+}
+
+template <typename T>
+inline typename std::enable_if<IsPrimitive<T>::value, zx_status_t>::type Clone(
+    const VectorPtr<T>& value, VectorPtr<T>* result) {
+  if (!value) {
+    *result = VectorPtr<T>();
+    return ZX_OK;
+  }
+  result->reset(*value);
+  return ZX_OK;
+}
+
+template <typename T, size_t N>
+inline zx_status_t Clone(const Array<T, N>& value, Array<T, N>* result) {
+  for (size_t i = 0; i < N; ++i) {
+    zx_status_t status = Clone(value[i], &result->at(i));
+    if (status != ZX_OK)
+      return status;
+  }
+  return ZX_OK;
+}
+
+zx_status_t Clone(const StringPtr& value, StringPtr* result);
+
+// Returns a deep copy of |value|.
+// This operation also attempts to duplicate any handles the value contains.
+//
+// Crashes the program if the value could not be cloned, perhaps because a
+// handle was not duplicable.
+template <typename T>
+inline T Clone(const T& value) {
+  T clone;
+  zx_status_t status = Clone(value, &clone);
+  ZX_ASSERT(status == ZX_OK);
+  return clone;
+}
+
+}  // namespace fidl
+
+#endif  // LIB_FIDL_CPP_CODING_TRAITS_H_
diff --git a/pkg/fidl_cpp_base/include/lib/fidl/cpp/coding_traits.h b/pkg/fidl_cpp_base/include/lib/fidl/cpp/coding_traits.h
new file mode 100644
index 0000000..0a51f5a
--- /dev/null
+++ b/pkg/fidl_cpp_base/include/lib/fidl/cpp/coding_traits.h
@@ -0,0 +1,165 @@
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef LIB_FIDL_CPP_CODING_TRAITS_H_
+#define LIB_FIDL_CPP_CODING_TRAITS_H_
+
+#include <lib/fidl/cpp/array.h>
+
+#include <memory>
+
+#include "lib/fidl/cpp/decoder.h"
+#include "lib/fidl/cpp/encoder.h"
+#include "lib/fidl/cpp/traits.h"
+#include "lib/fidl/cpp/vector.h"
+
+namespace fidl {
+
+template <typename T, class Enable = void>
+struct CodingTraits;
+
+template <typename T>
+struct CodingTraits<T, typename std::enable_if<IsPrimitive<T>::value>::type> {
+  static constexpr size_t encoded_size = sizeof(T);
+  inline static void Encode(Encoder* encoder, T* value, size_t offset) {
+    *encoder->GetPtr<T>(offset) = *value;
+  }
+  inline static void Decode(Decoder* decoder, T* value, size_t offset) {
+    *value = *decoder->GetPtr<T>(offset);
+  }
+};
+
+template <>
+struct CodingTraits<bool> {
+  static constexpr size_t encoded_size = sizeof(bool);
+  inline static void Encode(Encoder* encoder, bool* value, size_t offset) {
+    *encoder->GetPtr<bool>(offset) = *value;
+  }
+  inline static void Encode(Encoder* encoder, std::vector<bool>::iterator value,
+                            size_t offset) {
+    *encoder->GetPtr<bool>(offset) = *value;
+  }
+  inline static void Decode(Decoder* decoder, bool* value, size_t offset) {
+    *value = *decoder->GetPtr<bool>(offset);
+  }
+  inline static void Decode(Decoder* decoder, std::vector<bool>::iterator value,
+                            size_t offset) {
+    *value = *decoder->GetPtr<bool>(offset);
+  }
+};
+
+#ifdef __Fuchsia__
+template <typename T>
+struct CodingTraits<T, typename std::enable_if<
+                           std::is_base_of<zx::object_base, T>::value>::type> {
+  static constexpr size_t encoded_size = sizeof(zx_handle_t);
+  static void Encode(Encoder* encoder, zx::object_base* value, size_t offset) {
+    encoder->EncodeHandle(value, offset);
+  }
+  static void Decode(Decoder* decoder, zx::object_base* value, size_t offset) {
+    decoder->DecodeHandle(value, offset);
+  }
+};
+#endif
+
+template <typename T>
+struct CodingTraits<std::unique_ptr<T>> {
+  static constexpr size_t encoded_size = sizeof(uintptr_t);
+  static void Encode(Encoder* encoder, std::unique_ptr<T>* value,
+                     size_t offset) {
+    if (value->get()) {
+      *encoder->GetPtr<uintptr_t>(offset) = FIDL_ALLOC_PRESENT;
+      size_t size = CodingTraits<T>::encoded_size;
+      CodingTraits<T>::Encode(encoder, value->get(), encoder->Alloc(size));
+    } else {
+      *encoder->GetPtr<uintptr_t>(offset) = FIDL_ALLOC_ABSENT;
+    }
+  }
+  static void Decode(Decoder* decoder, std::unique_ptr<T>* value,
+                     size_t offset) {
+    uintptr_t ptr = *decoder->GetPtr<uintptr_t>(offset);
+    if (!ptr)
+      return value->reset();
+    *value = std::make_unique<T>();
+    CodingTraits<T>::Decode(decoder, value->get(), decoder->GetOffset(ptr));
+  }
+};
+
+void EncodeNullVector(Encoder* encoder, size_t offset);
+void EncodeVectorPointer(Encoder* encoder, size_t count, size_t offset);
+
+template <typename T>
+struct CodingTraits<VectorPtr<T>> {
+  static constexpr size_t encoded_size = sizeof(fidl_vector_t);
+  static void Encode(Encoder* encoder, VectorPtr<T>* value, size_t offset) {
+    if (value->is_null())
+      return EncodeNullVector(encoder, offset);
+    size_t count = (*value)->size();
+    EncodeVectorPointer(encoder, count, offset);
+    size_t stride = CodingTraits<T>::encoded_size;
+    size_t base = encoder->Alloc(count * stride);
+    for (size_t i = 0; i < count; ++i)
+      CodingTraits<T>::Encode(encoder, &(*value)->at(i), base + i * stride);
+  }
+  static void Decode(Decoder* decoder, VectorPtr<T>* value, size_t offset) {
+    fidl_vector_t* encoded = decoder->GetPtr<fidl_vector_t>(offset);
+    if (!encoded->data) {
+      *value = VectorPtr<T>();
+      return;
+    }
+    value->resize(encoded->count);
+    size_t stride = CodingTraits<T>::encoded_size;
+    size_t base = decoder->GetOffset(encoded->data);
+    size_t count = encoded->count;
+    for (size_t i = 0; i < count; ++i)
+      CodingTraits<T>::Decode(decoder, &(*value)->at(i), base + i * stride);
+  }
+};
+
+template <typename T, size_t N>
+struct CodingTraits<Array<T, N>> {
+  static constexpr size_t encoded_size = CodingTraits<T>::encoded_size * N;
+  static void Encode(Encoder* encoder, Array<T, N>* value, size_t offset) {
+    size_t stride = CodingTraits<T>::encoded_size;
+    for (size_t i = 0; i < N; ++i)
+      CodingTraits<T>::Encode(encoder, &value->at(i), offset + i * stride);
+  }
+  static void Decode(Decoder* decoder, Array<T, N>* value, size_t offset) {
+    size_t stride = CodingTraits<T>::encoded_size;
+    for (size_t i = 0; i < N; ++i)
+      CodingTraits<T>::Decode(decoder, &value->at(i), offset + i * stride);
+  }
+};
+
+template <typename T, size_t EncodedSize>
+struct EncodableCodingTraits {
+  static constexpr size_t encoded_size = EncodedSize;
+  static void Encode(Encoder* encoder, T* value, size_t offset) {
+    value->Encode(encoder, offset);
+  }
+  static void Decode(Decoder* decoder, T* value, size_t offset) {
+    T::Decode(decoder, value, offset);
+  }
+};
+
+template <typename T>
+void Encode(Encoder* encoder, T* value, size_t offset) {
+  CodingTraits<T>::Encode(encoder, value, offset);
+}
+
+template <typename T>
+void Decode(Decoder* decoder, T* value, size_t offset) {
+  CodingTraits<T>::Decode(decoder, value, offset);
+}
+
+template <typename T>
+T DecodeAs(Decoder* decoder, size_t offset) {
+  T value;
+  Decode(decoder, &value, offset);
+  return value;
+}
+
+}  // namespace fidl
+
+#endif  // LIB_FIDL_CPP_CODING_TRAITS_H_
diff --git a/pkg/fidl_cpp_base/include/lib/fidl/cpp/comparison.h b/pkg/fidl_cpp_base/include/lib/fidl/cpp/comparison.h
new file mode 100644
index 0000000..f89f352
--- /dev/null
+++ b/pkg/fidl_cpp_base/include/lib/fidl/cpp/comparison.h
@@ -0,0 +1,30 @@
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef GARNET_PUBLIC_LIB_FIDL_CPP_COMPARISON_H_
+#define GARNET_PUBLIC_LIB_FIDL_CPP_COMPARISON_H_
+
+#include <memory>
+
+// Comparisons that uses structure equality on on std::unique_ptr instead of
+// pointer equality.
+namespace fidl {
+
+template <class T>
+inline bool Equals(const T& lhs, const T& rhs) {
+  return lhs == rhs;
+}
+
+template <class T>
+inline bool Equals(const std::unique_ptr<T>& lhs,
+                   const std::unique_ptr<T>& rhs) {
+  if (lhs == nullptr || rhs == nullptr) {
+    return rhs == lhs;
+  }
+  return Equals<T>(*lhs, *rhs);
+}
+
+}  // namespace fidl
+
+#endif  // GARNET_PUBLIC_LIB_FIDL_CPP_COMPARISON_H_
diff --git a/pkg/fidl_cpp_base/include/lib/fidl/cpp/decoder.h b/pkg/fidl_cpp_base/include/lib/fidl/cpp/decoder.h
new file mode 100644
index 0000000..119dcd0
--- /dev/null
+++ b/pkg/fidl_cpp_base/include/lib/fidl/cpp/decoder.h
@@ -0,0 +1,42 @@
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef LIB_FIDL_CPP_DECODER_H_
+#define LIB_FIDL_CPP_DECODER_H_
+
+#include <lib/fidl/cpp/message.h>
+#include <zircon/fidl.h>
+
+#ifdef __Fuchsia__
+#include <lib/zx/object.h>
+#endif
+
+namespace fidl {
+
+class Decoder {
+ public:
+  explicit Decoder(Message message);
+  ~Decoder();
+
+  template <typename T>
+  T* GetPtr(size_t offset) {
+    return reinterpret_cast<T*>(InternalGetPtr(offset));
+  }
+
+  size_t GetOffset(void* ptr);
+  size_t GetOffset(uintptr_t ptr);
+
+#ifdef __Fuchsia__
+  void DecodeHandle(zx::object_base* value, size_t offset);
+#endif
+
+ private:
+  uint8_t* InternalGetPtr(size_t offset);
+
+  Message message_;
+};
+
+}  // namespace fidl
+
+#endif  // LIB_FIDL_CPP_DECODER_H_
diff --git a/pkg/fidl_cpp_base/include/lib/fidl/cpp/encoder.h b/pkg/fidl_cpp_base/include/lib/fidl/cpp/encoder.h
new file mode 100644
index 0000000..00f543e
--- /dev/null
+++ b/pkg/fidl_cpp_base/include/lib/fidl/cpp/encoder.h
@@ -0,0 +1,58 @@
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef LIB_FIDL_CPP_ENCODER_H_
+#define LIB_FIDL_CPP_ENCODER_H_
+
+#include <lib/fidl/cpp/message.h>
+
+#ifdef __Fuchsia__
+#include <lib/zx/object.h>
+#endif
+
+#include <zircon/fidl.h>
+
+#include <vector>
+
+namespace fidl {
+
+class Encoder {
+ public:
+  enum NoHeader { NO_HEADER };
+
+  explicit Encoder(uint32_t ordinal);
+  explicit Encoder(NoHeader) {}
+  ~Encoder();
+
+  size_t Alloc(size_t size);
+
+  template <typename T>
+  T* GetPtr(size_t offset) {
+    return reinterpret_cast<T*>(bytes_.data() + offset);
+  }
+
+#ifdef __Fuchsia__
+  void EncodeHandle(zx::object_base* value, size_t offset);
+#endif
+
+  Message GetMessage();
+
+  void Reset(uint32_t ordinal);
+
+  size_t CurrentLength() const { return bytes_.size(); }
+
+  size_t CurrentHandleCount() const { return handles_.size(); }
+
+  std::vector<uint8_t> TakeBytes() { return std::move(bytes_); }
+
+ private:
+  void EncodeMessageHeader(uint32_t ordinal);
+
+  std::vector<uint8_t> bytes_;
+  std::vector<zx_handle_t> handles_;
+};
+
+}  // namespace fidl
+
+#endif  // LIB_FIDL_CPP_ENCODER_H_
diff --git a/pkg/fidl_cpp_base/include/lib/fidl/cpp/internal/logging.h b/pkg/fidl_cpp_base/include/lib/fidl/cpp/internal/logging.h
new file mode 100644
index 0000000..4ed4132
--- /dev/null
+++ b/pkg/fidl_cpp_base/include/lib/fidl/cpp/internal/logging.h
@@ -0,0 +1,37 @@
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef LIB_FIDL_CPP_INTERNAL_LOGGING_H_
+#define LIB_FIDL_CPP_INTERNAL_LOGGING_H_
+
+#include <lib/fidl/cpp/message.h>
+
+namespace fidl {
+namespace internal {
+
+void ReportEncodingError(const Message& message, const fidl_type_t* type,
+                         const char* error_msg, const char* file, int line);
+
+void ReportDecodingError(const Message& message, const fidl_type_t* type,
+                         const char* error_msg, const char* file, int line);
+
+void ReportChannelWritingError(const Message& message, const fidl_type_t* type,
+                               zx_status_t status, const char* file, int line);
+
+#define FIDL_REPORT_ENCODING_ERROR(message, type, error_msg)            \
+  ::fidl::internal::ReportEncodingError((message), (type), (error_msg), \
+                                        __FILE__, __LINE__)
+
+#define FIDL_REPORT_DECODING_ERROR(message, type, error_msg)            \
+  ::fidl::internal::ReportDecodingError((message), (type), (error_msg), \
+                                        __FILE__, __LINE__)
+
+#define FIDL_REPORT_CHANNEL_WRITING_ERROR(message, type, status)           \
+  ::fidl::internal::ReportChannelWritingError((message), (type), (status), \
+                                              __FILE__, __LINE__)
+
+}  // namespace internal
+}  // namespace fidl
+
+#endif  // LIB_FIDL_CPP_INTERNAL_LOGGING_H_
diff --git a/pkg/fidl_cpp_base/include/lib/fidl/cpp/object_coding.h b/pkg/fidl_cpp_base/include/lib/fidl/cpp/object_coding.h
new file mode 100644
index 0000000..202b266
--- /dev/null
+++ b/pkg/fidl_cpp_base/include/lib/fidl/cpp/object_coding.h
@@ -0,0 +1,45 @@
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "coding_traits.h"
+#include "encoder.h"
+
+namespace fidl {
+
+template <class T>
+zx_status_t EncodeObject(T* object, std::vector<uint8_t>* output,
+                         const char** error_msg_out) {
+  Encoder encoder(Encoder::NO_HEADER);
+  object->Encode(&encoder, encoder.Alloc(CodingTraits<T>::encoded_size));
+  if (encoder.CurrentHandleCount() != 0) {
+    if (error_msg_out != nullptr) {
+      *error_msg_out = "Cannot encode handles with object encoding";
+    }
+    return ZX_ERR_INVALID_ARGS;
+  }
+  *output = encoder.TakeBytes();
+  return ZX_OK;
+}
+
+template <class T>
+zx_status_t DecodeObject(uint8_t* bytes, size_t bytes_length, T* object,
+                         const char** error_msg_out) {
+  Message msg(BytePart(bytes, bytes_length, bytes_length), HandlePart());
+  zx_status_t status = msg.Decode(T::FidlType, error_msg_out);
+  if (status != ZX_OK) {
+    return status;
+  }
+  Decoder decoder(std::move(msg));
+  T::Decode(&decoder, object, 0);
+  return ZX_OK;
+}
+
+template <class T>
+zx_status_t ValidateObject(uint8_t* bytes, size_t bytes_length, T* object,
+                           const char** error_msg_out) {
+  return Message(BytePart(bytes, bytes_length, bytes_length), HandlePart())
+      .Validate(T::FidlType, error_msg_out);
+}
+
+}  // namespace fidl
diff --git a/pkg/fidl_cpp_base/include/lib/fidl/cpp/string.h b/pkg/fidl_cpp_base/include/lib/fidl/cpp/string.h
new file mode 100644
index 0000000..3318bb7
--- /dev/null
+++ b/pkg/fidl_cpp_base/include/lib/fidl/cpp/string.h
@@ -0,0 +1,186 @@
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef LIB_FIDL_CPP_STRING_H_
+#define LIB_FIDL_CPP_STRING_H_
+
+#include <lib/fidl/cpp/builder.h>
+#include <lib/fidl/cpp/string_view.h>
+
+#include <iosfwd>
+#include <string>
+#include <utility>
+
+#include <zircon/assert.h>
+
+#include "lib/fidl/cpp/coding_traits.h"
+#include "lib/fidl/cpp/traits.h"
+
+namespace fidl {
+
+// A representation of a FIDL string that owns the memory for the string.
+//
+// A StringPtr has three states: (1) null, (2) empty, (3) contains a string. In
+// the second state, operations that return an std::string return the empty
+// std::string. The null and empty states can be distinguished using the
+// |is_null| and |operator bool| methods.
+class StringPtr {
+ public:
+  StringPtr();
+  StringPtr(const StringPtr& other);
+  StringPtr(StringPtr&& other);
+  StringPtr(std::string str);
+  StringPtr(const char* str);
+  StringPtr(const char* str, size_t length);
+  ~StringPtr();
+
+  StringPtr& operator=(const StringPtr&);
+  StringPtr& operator=(StringPtr&& other);
+
+  // Accesses the underlying std::string object.
+  const std::string& get() const { return str_; }
+
+  // Stores the given std::string in this StringPtr.
+  //
+  // After this method returns, the StringPtr is non-null.
+  void reset(std::string str) {
+    str_ = std::move(str);
+    is_null_ = false;
+  }
+
+  // Causes this StringPtr to become null.
+  void reset() {
+    str_.clear();
+    is_null_ = true;
+  }
+
+  void swap(StringPtr& other) {
+    using std::swap;
+    swap(str_, other.str_);
+    swap(is_null_, other.is_null_);
+  }
+
+  // Whether this StringPtr is null.
+  //
+  // The null state is separate from the empty state.
+  bool is_null() const { return is_null_ && str_.empty(); }
+
+  // Tests as true if non-null, false if null.
+  explicit operator bool() const { return !is_null_; }
+
+  // Provides access to the underlying std::string.
+  std::string* operator->() { return &str_; }
+  const std::string* operator->() const { return &str_; }
+
+  // Provides access to the underlying std::string.
+  const std::string& operator*() const { return str_; }
+
+  operator const std::string&() const { return str_; }
+
+  void Encode(Encoder* encoder, size_t offset);
+  static void Decode(Decoder* decoder, StringPtr* value, size_t offset);
+
+ private:
+  std::string str_;
+  bool is_null_;
+};
+
+inline bool operator==(const StringPtr& a, const StringPtr& b) {
+  if (a.is_null()) {
+    return b.is_null();
+  }
+  return !b.is_null() && a.get() == b.get();
+}
+
+inline bool operator==(const char* a, const StringPtr& b) {
+  if (a == nullptr) {
+    return b.is_null();
+  }
+  return !b.is_null() && a == b.get();
+}
+
+inline bool operator==(const StringPtr& a, const char* b) {
+  if (a.is_null()) {
+    return b == nullptr;
+  }
+  return b != nullptr && a.get() == b;
+}
+
+inline bool operator!=(const StringPtr& a, const StringPtr& b) {
+  return !(a == b);
+}
+
+inline bool operator!=(const char* a, const StringPtr& b) { return !(a == b); }
+
+inline bool operator!=(const StringPtr& a, const char* b) { return !(a == b); }
+
+inline bool operator<(const StringPtr& a, const StringPtr& b) {
+  if (a.is_null() || b.is_null()) {
+    return !b.is_null();
+  }
+  return *a < *b;
+}
+
+inline bool operator<(const char* a, const StringPtr& b) {
+  if (a == nullptr || b.is_null()) {
+    return !b.is_null();
+  }
+  return a < *b;
+}
+
+inline bool operator<(const StringPtr& a, const char* b) {
+  if (a.is_null() || b == nullptr) {
+    return b != nullptr;
+  }
+  return *a < b;
+}
+
+inline bool operator>(const StringPtr& a, const StringPtr& b) {
+  if (a.is_null() || b.is_null()) {
+    return !a.is_null();
+  }
+  return *a > *b;
+}
+
+inline bool operator>(const char* a, const StringPtr& b) {
+  if (a == nullptr || b.is_null()) {
+    return a != nullptr;
+  }
+  return a > *b;
+}
+
+inline bool operator>(const StringPtr& a, const char* b) {
+  if (a.is_null() || b == nullptr) {
+    return a != nullptr;
+  }
+  return *a > b;
+}
+
+inline bool operator<=(const StringPtr& a, const StringPtr& b) {
+  return !(a > b);
+}
+
+inline bool operator<=(const char* a, const StringPtr& b) { return !(a > b); }
+
+inline bool operator<=(const StringPtr& a, const char* b) { return !(a > b); }
+
+inline bool operator>=(const StringPtr& a, const StringPtr& b) {
+  return !(a < b);
+}
+
+inline bool operator>=(const char* a, const StringPtr& b) { return !(a < b); }
+
+inline bool operator>=(const StringPtr& a, const char* b) { return !(a < b); }
+
+inline std::ostream& operator<<(std::ostream& out, const StringPtr& str) {
+  return out << str.get();
+}
+
+template <>
+struct CodingTraits<StringPtr>
+    : public EncodableCodingTraits<StringPtr, sizeof(fidl_string_t)> {};
+
+}  // namespace fidl
+
+#endif  // LIB_FIDL_CPP_STRING_H_
diff --git a/pkg/fidl_cpp_base/include/lib/fidl/cpp/traits.h b/pkg/fidl_cpp_base/include/lib/fidl/cpp/traits.h
new file mode 100644
index 0000000..9ce7b3a
--- /dev/null
+++ b/pkg/fidl_cpp_base/include/lib/fidl/cpp/traits.h
@@ -0,0 +1,35 @@
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef LIB_FIDL_CPP_TRAITS_H_
+#define LIB_FIDL_CPP_TRAITS_H_
+
+#include <stdint.h>
+
+#include <type_traits>
+
+namespace fidl {
+
+// A type trait that indiciates whether the given type is a primitive FIDL
+// type.
+template <typename T>
+struct IsPrimitive : public std::false_type {};
+
+// clang-format off
+template <> struct IsPrimitive<bool> : public std::true_type {};
+template <> struct IsPrimitive<uint8_t> : public std::true_type {};
+template <> struct IsPrimitive<uint16_t> : public std::true_type {};
+template <> struct IsPrimitive<uint32_t> : public std::true_type {};
+template <> struct IsPrimitive<uint64_t> : public std::true_type {};
+template <> struct IsPrimitive<int8_t> : public std::true_type {};
+template <> struct IsPrimitive<int16_t> : public std::true_type {};
+template <> struct IsPrimitive<int32_t> : public std::true_type {};
+template <> struct IsPrimitive<int64_t> : public std::true_type {};
+template <> struct IsPrimitive<float> : public std::true_type {};
+template <> struct IsPrimitive<double> : public std::true_type {};
+// clang-format on
+
+}  // namespace fidl
+
+#endif  // LIB_FIDL_CPP_TRAITS_H_
diff --git a/pkg/fidl_cpp_base/include/lib/fidl/cpp/vector.h b/pkg/fidl_cpp_base/include/lib/fidl/cpp/vector.h
new file mode 100644
index 0000000..02d718c
--- /dev/null
+++ b/pkg/fidl_cpp_base/include/lib/fidl/cpp/vector.h
@@ -0,0 +1,183 @@
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef LIB_FIDL_CPP_VECTOR_H_
+#define LIB_FIDL_CPP_VECTOR_H_
+
+#include <lib/fidl/cpp/builder.h>
+#include <lib/fidl/cpp/comparison.h>
+#include <lib/fidl/cpp/vector_view.h>
+
+#include <utility>
+#include <vector>
+
+#include <zircon/assert.h>
+
+#include "lib/fidl/cpp/traits.h"
+
+namespace fidl {
+
+// A representation of a FIDL vector that owns the memory for the vector.
+//
+// A VectorPtr has three states: (1) null, (2) empty, (3) contains data.  You
+// can check for the null state using the |is_null| method.
+template <typename T>
+class VectorPtr {
+ public:
+  VectorPtr() : is_null_if_empty_(true) {}
+  ~VectorPtr() = default;
+  VectorPtr(std::nullptr_t) : is_null_if_empty_(true) {}
+  explicit VectorPtr(size_t size)
+      : vec_(std::vector<T>(size)), is_null_if_empty_(false) {}
+  explicit VectorPtr(std::vector<T> vec)
+      : vec_(std::move(vec)), is_null_if_empty_(false) {}
+
+  VectorPtr(const VectorPtr&) = delete;
+  VectorPtr& operator=(const VectorPtr&) = delete;
+
+  VectorPtr(VectorPtr&& other) = default;
+  VectorPtr& operator=(VectorPtr&& other) = default;
+
+  // Creates a VectorPtr of the given size.
+  //
+  // Equivalent to using the |VectorPtr(size_t)| constructor.
+  static VectorPtr New(size_t size) { return VectorPtr(size); }
+
+  // Accesses the underlying std::vector object.
+  const std::vector<T>& get() const { return vec_; }
+
+  // Takes the std::vector from the VectorPtr.
+  //
+  // After this method returns, the VectorPtr is null.
+  std::vector<T> take() {
+    is_null_if_empty_ = true;
+    return std::move(vec_);
+  }
+
+  // Stores the given std::vector in this VectorPtr.
+  //
+  // After this method returns, the VectorPtr is non-null.
+  void reset(std::vector<T> vec) {
+    vec_ = std::move(vec);
+    is_null_if_empty_ = false;
+  }
+
+  void reset() {
+    vec_.clear();
+    is_null_if_empty_ = true;
+  }
+
+  // Resizes the underlying std::vector in this VectorPtr to the given size.
+  //
+  // After this method returns, the VectorPtr is non-null.
+  void resize(size_t size) {
+    vec_.resize(size);
+    is_null_if_empty_ = false;
+  }
+
+  // Pushes |value| onto the back of this VectorPtr.
+  //
+  // If this vector was null, it will become non-null with a size of 1.
+  void push_back(const T& value) {
+    vec_.push_back(value);
+    is_null_if_empty_ = false;
+  }
+
+  // Pushes |value| onto the back of this VectorPtr.
+  //
+  // If this vector was null, it will become non-null with a size of 1.
+  void push_back(T&& value) {
+    vec_.push_back(std::forward<T>(value));
+    is_null_if_empty_ = false;
+  }
+
+  void swap(VectorPtr& other) {
+    using std::swap;
+    swap(vec_, other.vec_);
+    swap(is_null_if_empty_, other.is_null_if_empty_);
+  }
+
+  // Returns a copy of this VectorPtr.
+  //
+  // Unlike fidl::Clone, this function can never fail. However, this function
+  // works only if T is copiable.
+  VectorPtr Clone() const {
+    if (is_null())
+      return VectorPtr();
+    return VectorPtr(vec_);
+  }
+
+  // Whether this VectorPtr is null.
+  //
+  // The null state is separate from the empty state.
+  bool is_null() const { return is_null_if_empty_ && vec_.empty(); }
+
+  // Tests as true if non-null, false if null.
+  explicit operator bool() const { return !is_null(); }
+
+  // Provides access to the underlying std::vector.
+  std::vector<T>* operator->() { return &vec_; }
+  const std::vector<T>* operator->() const { return &vec_; }
+
+  // Provides access to the underlying std::vector.
+  std::vector<T>& operator*() { return vec_; }
+  const std::vector<T>& operator*() const { return vec_; }
+
+  operator const std::vector<T>&() const { return vec_; }
+
+ private:
+  std::vector<T> vec_;
+  bool is_null_if_empty_;
+};
+
+template <class T>
+inline bool operator==(const VectorPtr<T>& lhs, const VectorPtr<T>& rhs) {
+  if (lhs.is_null() || rhs.is_null()) {
+    return lhs.is_null() == rhs.is_null();
+  }
+  if (lhs->size() != rhs->size()) {
+    return false;
+  }
+  for (size_t i = 0; i < lhs->size(); ++i) {
+    if (!Equals(lhs->at(i), rhs->at(i))) {
+      return false;
+    }
+  }
+  return true;
+}
+
+template <class T>
+inline bool operator!=(const VectorPtr<T>& lhs, const VectorPtr<T>& rhs) {
+  return !(lhs == rhs);
+}
+
+template <class T>
+inline bool operator<(const VectorPtr<T>& lhs, const VectorPtr<T>& rhs) {
+  if (lhs.is_null() || rhs.is_null()) {
+    return !rhs.is_null();
+  }
+  return *lhs < *rhs;
+}
+
+template <class T>
+inline bool operator>(const VectorPtr<T>& lhs, const VectorPtr<T>& rhs) {
+  if (lhs.is_null() || rhs.is_null()) {
+    return !lhs.is_null();
+  }
+  return *lhs > *rhs;
+}
+
+template <class T>
+inline bool operator<=(const VectorPtr<T>& lhs, const VectorPtr<T>& rhs) {
+  return !(lhs > rhs);
+}
+
+template <class T>
+inline bool operator>=(const VectorPtr<T>& lhs, const VectorPtr<T>& rhs) {
+  return !(lhs < rhs);
+}
+
+}  // namespace fidl
+
+#endif  // LIB_FIDL_CPP_VECTOR_H_
diff --git a/pkg/fidl_cpp_base/internal/logging.cc b/pkg/fidl_cpp_base/internal/logging.cc
new file mode 100644
index 0000000..c9fd77d
--- /dev/null
+++ b/pkg/fidl_cpp_base/internal/logging.cc
@@ -0,0 +1,51 @@
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "lib/fidl/cpp/internal/logging.h"
+
+#include <inttypes.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+namespace fidl {
+namespace internal {
+
+void ReportEncodingError(const Message& message, const fidl_type_t* type,
+                         const char* error_msg, const char* file, int line) {
+  char type_name[1024];
+  size_t type_name_length =
+      fidl_format_type_name(type, type_name, sizeof(type_name));
+  fprintf(stderr,
+          "fidl encoding error at %s:%d: %s, "
+          "type %.*s, %" PRIu32 " bytes, %" PRIu32 " handles\n",
+          file, line, error_msg, static_cast<int>(type_name_length), type_name,
+          message.bytes().actual(), message.handles().actual());
+}
+
+void ReportDecodingError(const Message& message, const fidl_type_t* type,
+                         const char* error_msg, const char* file, int line) {
+  char type_name[1024];
+  size_t type_name_length =
+      fidl_format_type_name(type, type_name, sizeof(type_name));
+  fprintf(stderr,
+          "fidl decoding error at %s:%d: %s, "
+          "type %.*s, %" PRIu32 " bytes, %" PRIu32 " handles\n",
+          file, line, error_msg, static_cast<int>(type_name_length), type_name,
+          message.bytes().actual(), message.handles().actual());
+}
+
+void ReportChannelWritingError(const Message& message, const fidl_type_t* type,
+                               zx_status_t status, const char* file, int line) {
+  char type_name[1024];
+  size_t type_name_length =
+      fidl_format_type_name(type, type_name, sizeof(type_name));
+  fprintf(stderr,
+          "fidl channel writing error at %s:%d: zx_status_t %d, "
+          "type %.*s, %" PRIu32 " bytes, %" PRIu32 " handles\n",
+          file, line, status, static_cast<int>(type_name_length), type_name,
+          message.bytes().actual(), message.handles().actual());
+}
+
+}  // namespace internal
+}  // namespace fidl
diff --git a/pkg/fidl_cpp_base/meta.json b/pkg/fidl_cpp_base/meta.json
new file mode 100644
index 0000000..29eb264
--- /dev/null
+++ b/pkg/fidl_cpp_base/meta.json
@@ -0,0 +1,34 @@
+{
+  "deps": [
+    "fit", 
+    "fidl", 
+    "fidl-async", 
+    "zx"
+  ], 
+  "fidl_deps": [], 
+  "headers": [
+    "pkg/fidl_cpp_base/include/lib/fidl/cpp/array.h", 
+    "pkg/fidl_cpp_base/include/lib/fidl/cpp/clone.h", 
+    "pkg/fidl_cpp_base/include/lib/fidl/cpp/coding_traits.h", 
+    "pkg/fidl_cpp_base/include/lib/fidl/cpp/comparison.h", 
+    "pkg/fidl_cpp_base/include/lib/fidl/cpp/decoder.h", 
+    "pkg/fidl_cpp_base/include/lib/fidl/cpp/encoder.h", 
+    "pkg/fidl_cpp_base/include/lib/fidl/cpp/internal/logging.h", 
+    "pkg/fidl_cpp_base/include/lib/fidl/cpp/object_coding.h", 
+    "pkg/fidl_cpp_base/include/lib/fidl/cpp/string.h", 
+    "pkg/fidl_cpp_base/include/lib/fidl/cpp/traits.h", 
+    "pkg/fidl_cpp_base/include/lib/fidl/cpp/vector.h"
+  ], 
+  "include_dir": "pkg/fidl_cpp_base/include", 
+  "name": "fidl_cpp_base", 
+  "root": "pkg/fidl_cpp_base", 
+  "sources": [
+    "pkg/fidl_cpp_base/clone.cc", 
+    "pkg/fidl_cpp_base/coding_traits.cc", 
+    "pkg/fidl_cpp_base/decoder.cc", 
+    "pkg/fidl_cpp_base/encoder.cc", 
+    "pkg/fidl_cpp_base/internal/logging.cc", 
+    "pkg/fidl_cpp_base/string.cc"
+  ], 
+  "type": "cc_source_library"
+}
\ No newline at end of file
diff --git a/pkg/fidl_cpp_base/string.cc b/pkg/fidl_cpp_base/string.cc
new file mode 100644
index 0000000..35b8f46
--- /dev/null
+++ b/pkg/fidl_cpp_base/string.cc
@@ -0,0 +1,61 @@
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "lib/fidl/cpp/string.h"
+
+#include <string.h>
+
+#include "lib/fidl/cpp/encoder.h"
+
+namespace fidl {
+
+StringPtr::StringPtr() : is_null_(true) {}
+
+StringPtr::StringPtr(const StringPtr& other) = default;
+
+StringPtr::StringPtr(std::string str) : str_(std::move(str)), is_null_(false) {}
+
+StringPtr::StringPtr(const char* str)
+    : str_(str ? std::string(str) : std::string()), is_null_(!str) {}
+
+StringPtr::StringPtr(const char* str, size_t length)
+    : str_(str ? std::string(str, length) : std::string()), is_null_(!str) {}
+
+StringPtr::~StringPtr() = default;
+
+StringPtr::StringPtr(StringPtr&& other)
+    : str_(std::move(other.str_)), is_null_(other.is_null_) {}
+
+StringPtr& StringPtr::operator=(const StringPtr& other) = default;
+
+StringPtr& StringPtr::operator=(StringPtr&& other) {
+  str_ = std::move(other.str_);
+  is_null_ = other.is_null_;
+  return *this;
+}
+
+void StringPtr::Encode(Encoder* encoder, size_t offset) {
+  fidl_string_t* string = encoder->GetPtr<fidl_string_t>(offset);
+  if (is_null()) {
+    string->size = 0u;
+    string->data = reinterpret_cast<char*>(FIDL_ALLOC_ABSENT);
+  } else {
+    string->size = str_.size();
+    string->data = reinterpret_cast<char*>(FIDL_ALLOC_PRESENT);
+    size_t base = encoder->Alloc(str_.size());
+    char* payload = encoder->GetPtr<char>(base);
+    memcpy(payload, str_.data(), str_.size());
+  }
+}
+
+void StringPtr::Decode(Decoder* decoder, StringPtr* value, size_t offset) {
+  fidl_string_t* string = decoder->GetPtr<fidl_string_t>(offset);
+  if (string->data) {
+    value->reset(std::string(string->data, string->size));
+  } else {
+    *value = StringPtr();
+  }
+}
+
+}  // namespace fidl
diff --git a/pkg/fidl_cpp_sync/include/lib/fidl/cpp/interface_handle.h b/pkg/fidl_cpp_sync/include/lib/fidl/cpp/interface_handle.h
new file mode 100644
index 0000000..2257a00
--- /dev/null
+++ b/pkg/fidl_cpp_sync/include/lib/fidl/cpp/interface_handle.h
@@ -0,0 +1,186 @@
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef LIB_FIDL_CPP_INTERFACE_HANDLE_H_
+#define LIB_FIDL_CPP_INTERFACE_HANDLE_H_
+
+#include <lib/zx/channel.h>
+#include <zircon/assert.h>
+
+#include <cstddef>
+#include <utility>
+
+#include "lib/fidl/cpp/clone.h"
+#include "lib/fidl/cpp/coding_traits.h"
+#include "lib/fidl/cpp/interface_request.h"
+
+namespace fidl {
+class Builder;
+template <typename Interface>
+class InterfacePtr;
+template <typename Interface>
+class SynchronousInterfacePtr;
+
+// The client endpoint of a FIDL channel.
+//
+// The remote end of the channel expects this end of the channel to speak the
+// protocol associated with |Interface|. This type is the dual of
+// |InterfaceRequest|.
+//
+// Unlike an |InterfacePtr|, an |InterfaceHandle| does not have thread affinity
+// and can therefore be transferred to another thread or another process. To
+// create an |InterfacePtr| to send messages on this channel, call the |Bind()|
+// method, either on the |InterfaceHandle| or the |InterfacePtr| object.
+//
+// See also:
+//
+//  * |InterfaceRequest|, which is the server analog of an |InterfaceHandle|.
+template <typename Interface>
+class InterfaceHandle {
+ public:
+  // Creates an |InterfaceHandle| whose underlying channel is invalid.
+  InterfaceHandle() = default;
+
+  // Creates an |InterfaceHandle| that wraps the given |channel|.
+  explicit InterfaceHandle(zx::channel channel)
+      : channel_(std::move(channel)) {}
+
+  InterfaceHandle(const InterfaceHandle& other) = delete;
+  InterfaceHandle& operator=(const InterfaceHandle& other) = delete;
+
+  InterfaceHandle(InterfaceHandle&& other)
+      : channel_(std::move(other.channel_)) {}
+
+  InterfaceHandle& operator=(InterfaceHandle&& other) {
+    channel_ = std::move(other.channel_);
+    return *this;
+  }
+
+  // Implicit conversion from nullptr to an |InterfaceHandle| without a valid
+  // |channel|.
+  InterfaceHandle(std::nullptr_t) {}
+
+  // Implicit conversion from |InterfacePtr| unbinds the channel from the
+  // |InterfacePtr|.
+  //
+  // Making this constructor templated ensures that it is not type-instantiated
+  // unless it is used, making the InterfacePtr<->InterfaceHandle codependency
+  // less fragile.
+  template <typename InterfacePtr = InterfacePtr<Interface>>
+  InterfaceHandle(InterfacePtr&& ptr) {
+    *this = ptr.Unbind();
+  }
+
+  // Creates a new channel, retains one endpoint in this |InterfaceHandle| and
+  // returns the other as an |InterfaceRequest|.
+  //
+  // Typically, the returned |InterfaceRequest| is passed to another process,
+  // which will implement the server endpoint for the |Interface| protocol.
+  //
+  // If |NewRequest| fails to create the underlying channel, the returned
+  // |InterfaceRequest| will return false from |is_valid()|.
+  InterfaceRequest<Interface> NewRequest() {
+    zx::channel h1, h2;
+    if (zx::channel::create(0, &h1, &h2) != ZX_OK)
+      return nullptr;
+    channel_ = std::move(h1);
+    return InterfaceRequest<Interface>(std::move(h2));
+  }
+
+  // Creates an |InterfacePtr| bound to the channel in this |InterfaceHandle|.
+  //
+  // This function transfers ownership of the underlying channel to the
+  // returned |InterfacePtr|, which means the |is_valid()| method will return
+  // false after this method returns.
+  //
+  // Requires the current thread to have a default async_t (e.g., a message
+  // loop) in order to read messages from the channel and to monitor the
+  // channel for |ZX_CHANNEL_PEER_CLOSED|.
+  //
+  // Making this method templated ensures that it is not type-instantiated
+  // unless it is used, making the InterfacePtr<->InterfaceHandle codependency
+  // less fragile.
+  template <typename InterfacePtr = InterfacePtr<Interface>>
+  inline InterfacePtr Bind() {
+    InterfacePtr ptr;
+    ptr.Bind(std::move(channel_));
+    return ptr;
+  }
+
+  template <typename SyncInterfacePtr = SynchronousInterfacePtr<Interface>>
+  inline SyncInterfacePtr BindSync() {
+    SyncInterfacePtr ptr;
+    ptr.Bind(std::move(channel_));
+    return ptr;
+  }
+
+  // Whether the underlying channel is valid.
+  bool is_valid() const { return !!channel_; }
+  explicit operator bool() const { return is_valid(); }
+
+  // Transfers ownership of the underlying channel to the caller.
+  zx::channel TakeChannel() { return std::move(channel_); }
+
+  // The underlying channel.
+  const zx::channel& channel() const { return channel_; }
+  void set_channel(zx::channel channel) { channel_ = std::move(channel); }
+
+  void Encode(Encoder* encoder, size_t offset) {
+    encoder->EncodeHandle(&channel_, offset);
+  }
+
+  static void Decode(Decoder* decoder, InterfaceHandle<Interface>* value,
+                     size_t offset) {
+    decoder->DecodeHandle(&value->channel_, offset);
+  }
+
+ private:
+  zx::channel channel_;
+};
+
+// Equality.
+template <typename T>
+bool operator==(const InterfaceHandle<T>& lhs, const InterfaceHandle<T>& rhs) {
+  return lhs.channel() == rhs.channel();
+}
+template <typename T>
+bool operator!=(const InterfaceHandle<T>& lhs, const InterfaceHandle<T>& rhs) {
+  return !(lhs == rhs);
+}
+
+// Comparisons.
+template <typename T>
+bool operator<(const InterfaceHandle<T>& lhs, const InterfaceHandle<T>& rhs) {
+  return lhs.channel() < rhs.channel();
+}
+template <typename T>
+bool operator>(const InterfaceHandle<T>& lhs, const InterfaceHandle<T>& rhs) {
+  return lhs.channel() > rhs.channel();
+}
+template <typename T>
+bool operator<=(const InterfaceHandle<T>& lhs, const InterfaceHandle<T>& rhs) {
+  return !(lhs > rhs);
+}
+template <typename T>
+bool operator>=(const InterfaceHandle<T>& lhs, const InterfaceHandle<T>& rhs) {
+  return !(lhs < rhs);
+}
+
+template <typename T>
+struct CodingTraits<InterfaceHandle<T>>
+    : public EncodableCodingTraits<InterfaceHandle<T>, sizeof(zx_handle_t)> {};
+
+template <typename T>
+inline zx_status_t Clone(const InterfaceHandle<T>& value,
+                         InterfaceHandle<T>* result) {
+  if (!value) {
+    *result = InterfaceHandle<T>();
+    return ZX_OK;
+  }
+  return ZX_ERR_ACCESS_DENIED;
+}
+
+}  // namespace fidl
+
+#endif  // LIB_FIDL_CPP_INTERFACE_HANDLE_H_
diff --git a/pkg/fidl_cpp_sync/include/lib/fidl/cpp/interface_request.h b/pkg/fidl_cpp_sync/include/lib/fidl/cpp/interface_request.h
new file mode 100644
index 0000000..45af19c
--- /dev/null
+++ b/pkg/fidl_cpp_sync/include/lib/fidl/cpp/interface_request.h
@@ -0,0 +1,171 @@
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef LIB_FIDL_CPP_INTERFACE_REQUEST_H_
+#define LIB_FIDL_CPP_INTERFACE_REQUEST_H_
+
+#include <lib/fit/function.h>
+#include <lib/zx/channel.h>
+
+#include <cstddef>
+#include <utility>
+
+#include "lib/fidl/cpp/clone.h"
+#include "lib/fidl/cpp/coding_traits.h"
+
+namespace fidl {
+class Builder;
+
+// The server endpoint of a FIDL channel.
+//
+// The remote end of the channel expects this end of the channel to speak the
+// protocol associated with |Interface|. This type is the dual of
+// |InterfaceHandle|.
+//
+// An |InterfaceRequest| does not have thread affinity and can therefore be
+// transferred to another thread or another process. To bind an implementation
+// of |Interface| to this |InterfaceRequest|, use a |Binding| object.
+//
+// Typically, |InterfaceRequest| objects are created by a prospective client of
+// |Interface|, which then sends the |InterfaceRequest| to another process to
+// request that the remote process implement the |Interface|. This pattern
+// enables *pipelined* operation, in which the client can start calling methods
+// on an associated |InterfacePtr| immediately, before the |InterfaceRequest|
+// has reached the remote process and been bound to an implementation. These
+// method calls are buffered by the underlying channel until they are read by
+// the remote process.
+//
+// Example:
+//
+//   #include "foo.fidl.h"
+//
+//   class FooImpl : public Foo {
+//    public:
+//     explicit FooImpl(InterfaceRequest<Foo> request)
+//         : binding_(this, std::move(request)) {}
+//
+//     // Foo implementation here.
+//
+//    private:
+//     Binding<Foo> binding_;
+//   };
+//
+// After the |InterfaceRequest| has been bound to an implementation, the
+// implementation will receive method calls from the remote endpoint of the
+// channel on the thread on which the |InterfaceRequest| was bound.
+//
+// See also:
+//
+//  * |InterfaceHandle|, which is the client analog of an |InterfaceRequest|.
+template <typename Interface>
+class InterfaceRequest {
+ public:
+  // Creates an |InterfaceHandle| whose underlying channel is invalid.
+  //
+  // Some protocols contain messages that permit such |InterfaceRequest|
+  // objects, which indicate that the client is not interested in the server
+  // providing an implementation of |Interface|.
+  InterfaceRequest() = default;
+
+  // Creates an |InterfaceHandle| that wraps the given |channel|.
+  explicit InterfaceRequest(zx::channel channel)
+      : channel_(std::move(channel)) {}
+
+  InterfaceRequest(const InterfaceRequest& other) = delete;
+  InterfaceRequest& operator=(const InterfaceRequest& other) = delete;
+
+  InterfaceRequest(InterfaceRequest&& other)
+      : channel_(std::move(other.channel_)) {}
+
+  InterfaceRequest& operator=(InterfaceRequest&& other) {
+    channel_ = std::move(other.channel_);
+    return *this;
+  }
+
+  // Implicit conversion from nullptr to an |InterfaceRequest| without an
+  // invalid |channel|.
+  InterfaceRequest(std::nullptr_t) {}
+
+  // Whether the underlying channel is valid.
+  bool is_valid() const { return !!channel_; }
+  explicit operator bool() const { return is_valid(); }
+
+  // Transfers ownership of the underlying channel to the caller.
+  zx::channel TakeChannel() { return std::move(channel_); }
+
+  // The underlying channel.
+  const zx::channel& channel() const { return channel_; }
+  void set_channel(zx::channel channel) { channel_ = std::move(channel); }
+
+  void Encode(Encoder* encoder, size_t offset) {
+    encoder->EncodeHandle(&channel_, offset);
+  }
+
+  static void Decode(Decoder* decoder, InterfaceRequest<Interface>* value,
+                     size_t offset) {
+    decoder->DecodeHandle(&value->channel_, offset);
+  }
+
+ private:
+  zx::channel channel_;
+};
+
+// A |InterfaceRequestHandler<Interface>| is simply a function that
+// handles an interface request for |Interface|. If it determines that the
+// request should be "accepted", then it should "connect" ("take ownership
+// of") request. Otherwise, it can simply drop |request| (as implied by the
+// interface).
+template <typename Interface>
+using InterfaceRequestHandler =
+    fit::function<void(fidl::InterfaceRequest<Interface> request)>;
+
+// Equality.
+template <typename T>
+bool operator==(const InterfaceRequest<T>& lhs,
+                const InterfaceRequest<T>& rhs) {
+  return lhs.channel() == rhs.channel();
+}
+template <typename T>
+bool operator!=(const InterfaceRequest<T>& lhs,
+                const InterfaceRequest<T>& rhs) {
+  return !(lhs == rhs);
+}
+
+// Comparaisons.
+template <typename T>
+bool operator<(const InterfaceRequest<T>& lhs, const InterfaceRequest<T>& rhs) {
+  return lhs.channel() < rhs.channel();
+}
+template <typename T>
+bool operator>(const InterfaceRequest<T>& lhs, const InterfaceRequest<T>& rhs) {
+  return lhs.channel() > rhs.channel();
+}
+template <typename T>
+bool operator<=(const InterfaceRequest<T>& lhs,
+                const InterfaceRequest<T>& rhs) {
+  return !(lhs > rhs);
+}
+template <typename T>
+bool operator>=(const InterfaceRequest<T>& lhs,
+                const InterfaceRequest<T>& rhs) {
+  return !(lhs < rhs);
+}
+
+template <typename T>
+struct CodingTraits<InterfaceRequest<T>>
+    : public EncodableCodingTraits<InterfaceRequest<T>, sizeof(zx_handle_t)> {};
+
+template <typename T>
+inline zx_status_t Clone(const InterfaceRequest<T>& value,
+                         InterfaceRequest<T>* result) {
+  if (!value) {
+    *result = InterfaceRequest<T>();
+    return ZX_OK;
+  }
+  return ZX_ERR_ACCESS_DENIED;
+}
+
+}  // namespace fidl
+
+#endif  // LIB_FIDL_CPP_INTERFACE_REQUEST_H_
diff --git a/pkg/fidl_cpp_sync/include/lib/fidl/cpp/internal/synchronous_proxy.h b/pkg/fidl_cpp_sync/include/lib/fidl/cpp/internal/synchronous_proxy.h
new file mode 100644
index 0000000..ee77c99
--- /dev/null
+++ b/pkg/fidl_cpp_sync/include/lib/fidl/cpp/internal/synchronous_proxy.h
@@ -0,0 +1,61 @@
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef LIB_FIDL_CPP_INTERNAL_SYNCHRONOUS_PROXY_H_
+#define LIB_FIDL_CPP_INTERNAL_SYNCHRONOUS_PROXY_H_
+
+#include <lib/fidl/cpp/message.h>
+#include <lib/zx/channel.h>
+#include <zircon/fidl.h>
+
+namespace fidl {
+namespace internal {
+
+// Manages the client state for a synchronous interface.
+//
+// A |SynchronousProxy| manages the client state for a sychronous interface.
+// This object validates messages before sending them to the remote endpoint,
+// and (optionally) blocks until it receives a reply.
+//
+// This object is thread-safe.
+class SynchronousProxy {
+ public:
+  // Creates a |SynchronousProxy| that wraps the given channel.
+  explicit SynchronousProxy(zx::channel channel);
+  ~SynchronousProxy();
+
+  // Returns the underlying channel from this object.
+  //
+  // The |SynchronousProxy| does not attempt to synchronize this operation with
+  // |Send| or |Call|.
+  zx::channel TakeChannel();
+
+  // Validates that |message| matches the given |type| and sends the message
+  // through the underlying channel.
+  //
+  // Does not block.
+  //
+  // Returns an error if validation or writing fails.
+  zx_status_t Send(const fidl_type_t* type, Message message);
+
+  // Validate that |request| matches the given |request_type| and sends
+  // |request| through the underlying channel. Blocks until it receives a
+  // response, which is then decoded according to |response_type| and returned
+  // in |response_type|.
+  //
+  // Blocks until the remote endpoint replied.
+  //
+  // Returns an error if validation, writing, reading, or decoding fails.
+  zx_status_t Call(const fidl_type_t* request_type,
+                   const fidl_type_t* response_type, Message request,
+                   Message* response);
+
+ private:
+  zx::channel channel_;
+};
+
+}  // namespace internal
+}  // namespace fidl
+
+#endif  // LIB_FIDL_CPP_INTERNAL_SYNCHRONOUS_PROXY_H_
diff --git a/pkg/fidl_cpp_sync/include/lib/fidl/cpp/synchronous_interface_ptr.h b/pkg/fidl_cpp_sync/include/lib/fidl/cpp/synchronous_interface_ptr.h
new file mode 100644
index 0000000..7f9ff6c
--- /dev/null
+++ b/pkg/fidl_cpp_sync/include/lib/fidl/cpp/synchronous_interface_ptr.h
@@ -0,0 +1,185 @@
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef LIB_FIDL_CPP_SYNCHRONOUS_INTERFACE_PTR_H_
+#define LIB_FIDL_CPP_SYNCHRONOUS_INTERFACE_PTR_H_
+
+#include <stddef.h>
+
+#include <memory>
+#include <utility>
+
+#include "lib/fidl/cpp/interface_handle.h"
+
+namespace fidl {
+
+// A synchronous client interface to a remote implementation of |Interface|.
+//
+// An |SynchronousInterfacePtr| implements |Interface| by proxying calls through
+// a |channel| to a remote implementation of |Interface|. Method calls on the
+// |Interface| proxy are encoded and sent through the bound channel to the
+// remote endpoint, which processes them. If the method has a reply (including
+// any empty reply), the client blocks and waits for the remote endpoint to
+// reply.
+//
+// You need to bind the |SynchronousInterfacePtr| before calling any |Interface|
+// methods. There are a number of ways to bind the |SynchronousInterfacePtr|.
+// See |NewRequest|, |Bind|, and the |BindSync| method on |InterfaceHandle|.
+//
+// This class is thread-compatible. Once bound, the |SynchronousInterfacePtr|
+// can be used from multiple threads simultaneously. However, the
+// |SynchronousInterfacePtr| does not attempt to synchronize mutating operatios,
+// such as |Bind| or |Unbind|.
+//
+// |SynchronousInterfacePtr| does not require a |async_t| implementation and
+// does not bind to the default |async_dispatcher_t*| for the current thread,
+// unlike |InterfacePtr|.
+//
+// See also:
+//
+//  * |Binding|, which is the server analog of an |SynchronousInterfacePtr|.
+//  * |InterfacePtr|, which is an asynchronous interface to a remote
+//    implementation.
+template <typename Interface>
+class SynchronousInterfacePtr {
+ public:
+  using InterfaceSync = typename Interface::Sync_;
+
+  // Creates an unbound |SynchronousInterfacePtr|.
+  SynchronousInterfacePtr() {}
+  SynchronousInterfacePtr(std::nullptr_t) {}
+
+  SynchronousInterfacePtr(const SynchronousInterfacePtr& other) = delete;
+  SynchronousInterfacePtr& operator=(const SynchronousInterfacePtr& other) =
+      delete;
+
+  SynchronousInterfacePtr(SynchronousInterfacePtr&& other) = default;
+  SynchronousInterfacePtr& operator=(SynchronousInterfacePtr&& other) = default;
+
+  // Bind the |SynchronousInterfacePtr| to one endpoint of a newly created
+  // channel and return the other endpoint as an |InterfaceRequest|.
+  //
+  // Typically, the returned |InterfaceRequest| will be sent to a remote process
+  // to be bound to an implementation of |Interface| using a |Binding| object.
+  //
+  // After calling this method, clients can start calling methods on this
+  // |SynchronousInterfacePtr|. However, methods that have replies will block
+  // until the remote implementation binds the |InterfaceRequest| and replies.
+  //
+  // # Example
+  //
+  // Given the following interface:
+  //
+  //   interface Database {
+  //     OpenTable(request<Table> table);
+  //   };
+  //
+  // The client can use the |NewRequest| method to create the |InterfaceRequest|
+  // object needed by the |OpenTable| method:
+  //
+  //   DatabasePtr database = ...;  // Connect to database.
+  //   TableSyncPtr table;
+  //   database->OpenTable(table.NewRequest());
+  //
+  // The client can call methods on |table| immediately. Messages that have
+  // replies will block until the Database implementation binds a Table
+  // implementation and replies.
+  InterfaceRequest<Interface> NewRequest() {
+    zx::channel h1;
+    zx::channel h2;
+    if (zx::channel::create(0, &h1, &h2) != ZX_OK)
+      return nullptr;
+    Bind(std::move(h1));
+    return InterfaceRequest<Interface>(std::move(h2));
+  }
+
+  // Binds the |SynchronousInterfacePtr| to the given |channel|.
+  //
+  // The |SynchronousInterfacePtr| expects the remote end of the |channel| to
+  // speak the protocol defined by |Interface|. Unlike the |Bind| overload that
+  // takes a |InterfaceHandle| parameter, this |Bind| overload lacks type
+  // safety.
+  //
+  // If the |SynchronousInterfacePtr| was prevously bound to another channel,
+  // that channel is closed. If the |channel| is invalid, then this method will
+  // effectively unbind the |SynchronousInterfacePtr|. A more direct way to have
+  // that effect is to call |Unbind|.
+  //
+  // Does not require the current thread to have a default async_t.
+  void Bind(zx::channel channel) {
+    if (!channel) {
+      proxy_.reset();
+      return;
+    }
+    proxy_.reset(new typename InterfaceSync::Proxy_(std::move(channel)));
+  }
+
+  // Binds the |SynchronousInterfacePtr| to the given |InterfaceHandle|.
+  //
+  // The |SynchronousInterfacePtr| expects the remote end of the |channel| to
+  // speak the protocol defined by |Interface|. Unlike the |Bind| overload that
+  // takes a |channel| parameter, this |Bind| overload provides type safety.
+  //
+  // If the |SynchronousInterfacePtr| was prevously bound to another channel,
+  // that channel is closed. If the |InterfaceHandle| is invalid, then this
+  // method will effectively unbind the |SynchronousInterfacePtr|. A more direct
+  // way to have that effect is to call |Unbind|.
+  //
+  // Does not require the current thread to have a default async_t.
+  void Bind(InterfaceHandle<Interface> handle) {
+    return Bind(handle.TakeChannel());
+  }
+
+  // Unbinds the underlying channel from the |SynchronousInterfacePtr|.
+  //
+  // The underlying channel is returned as an |InterfaceHandle|, which is safe
+  // to transport to another thread or process.
+  //
+  // After this method returns, a subsequent call to |Bind| is required before
+  // calling any additional |Interface| methods.
+  InterfaceHandle<Interface> Unbind() {
+    InterfaceHandle<Interface> handle(proxy_->proxy().TakeChannel());
+    proxy_.reset();
+    return handle;
+  }
+
+  // Whether this |SynchronousInterfacePtr| is currently bound to a channel.
+  //
+  // If the |SynchronousInterfacePtr| is bound to a channel, calls to
+  // |Interface| methods are proxied to the remote endpoint of the channel.
+  //
+  // See also:
+  //
+  //  * |Bind|, which binds a channel to this |SynchronousInterfacePtr|.
+  //  * |Unbind|, which unbinds a channel from this |SynchronousInterfacePtr|.
+  bool is_bound() const { return static_cast<bool>(proxy_); }
+
+  // Whether this |SynchronousInterfacePtr| is currently bound to a channel.
+  //
+  // See |is_bound| for details.
+  explicit operator bool() const { return is_bound(); }
+
+  // The |Interface| proxy associated with this |SynchronousInterfacePtr|.
+  //
+  // When this |SynchronousInterfacePtr| is bound, method calls on this
+  // |Interface| will be proxied to the remote endpoint of the connection.
+  // Methods that expect replies will block until the
+  // |SynchronousInterfacePtr| either receives a reply to that transaction.
+  //
+  // When this |SynchronousInterfacePtr| is not bound, this method returns
+  // nullptr.
+  //
+  // The returned |Interface| is thread-compatible and can be used from any
+  // thread.
+  InterfaceSync* get() const { return proxy_.get(); }
+  InterfaceSync* operator->() const { return get(); }
+  InterfaceSync& operator*() const { return *get(); }
+
+ private:
+  std::unique_ptr<typename InterfaceSync::Proxy_> proxy_;
+};
+
+}  // namespace fidl
+
+#endif  // LIB_FIDL_CPP_SYNCHRONOUS_INTERFACE_PTR_H_
diff --git a/pkg/fidl_cpp_sync/internal/synchronous_proxy.cc b/pkg/fidl_cpp_sync/internal/synchronous_proxy.cc
new file mode 100644
index 0000000..0e42e56
--- /dev/null
+++ b/pkg/fidl_cpp_sync/internal/synchronous_proxy.cc
@@ -0,0 +1,53 @@
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "lib/fidl/cpp/internal/synchronous_proxy.h"
+
+#include <memory>
+#include <utility>
+
+#include "lib/fidl/cpp/internal/logging.h"
+
+namespace fidl {
+namespace internal {
+
+SynchronousProxy::SynchronousProxy(zx::channel channel)
+    : channel_(std::move(channel)) {}
+
+SynchronousProxy::~SynchronousProxy() = default;
+
+zx::channel SynchronousProxy::TakeChannel() { return std::move(channel_); }
+
+zx_status_t SynchronousProxy::Send(const fidl_type_t* type, Message message) {
+  const char* error_msg = nullptr;
+  zx_status_t status = message.Validate(type, &error_msg);
+  if (status != ZX_OK) {
+    FIDL_REPORT_ENCODING_ERROR(message, type, error_msg);
+    return status;
+  }
+  return message.Write(channel_.get(), 0);
+}
+
+zx_status_t SynchronousProxy::Call(const fidl_type_t* request_type,
+                                   const fidl_type_t* response_type,
+                                   Message request, Message* response) {
+  const char* error_msg = nullptr;
+  zx_status_t status = request.Validate(request_type, &error_msg);
+  if (status != ZX_OK) {
+    FIDL_REPORT_ENCODING_ERROR(request, request_type, error_msg);
+    return status;
+  }
+  status = request.Call(channel_.get(), 0, ZX_TIME_INFINITE, response);
+  if (status != ZX_OK)
+    return status;
+  status = response->Decode(response_type, &error_msg);
+  if (status != ZX_OK) {
+    FIDL_REPORT_DECODING_ERROR(*response, response_type, error_msg);
+    return status;
+  }
+  return ZX_OK;
+}
+
+}  // namespace internal
+}  // namespace fidl
diff --git a/pkg/fidl_cpp_sync/meta.json b/pkg/fidl_cpp_sync/meta.json
new file mode 100644
index 0000000..c74ae9d
--- /dev/null
+++ b/pkg/fidl_cpp_sync/meta.json
@@ -0,0 +1,23 @@
+{
+  "deps": [
+    "fidl_cpp_base", 
+    "fidl", 
+    "fidl-async", 
+    "fit", 
+    "zx"
+  ], 
+  "fidl_deps": [], 
+  "headers": [
+    "pkg/fidl_cpp_sync/include/lib/fidl/cpp/interface_handle.h", 
+    "pkg/fidl_cpp_sync/include/lib/fidl/cpp/interface_request.h", 
+    "pkg/fidl_cpp_sync/include/lib/fidl/cpp/internal/synchronous_proxy.h", 
+    "pkg/fidl_cpp_sync/include/lib/fidl/cpp/synchronous_interface_ptr.h"
+  ], 
+  "include_dir": "pkg/fidl_cpp_sync/include", 
+  "name": "fidl_cpp_sync", 
+  "root": "pkg/fidl_cpp_sync", 
+  "sources": [
+    "pkg/fidl_cpp_sync/internal/synchronous_proxy.cc"
+  ], 
+  "type": "cc_source_library"
+}
\ No newline at end of file
diff --git a/pkg/fit/include/lib/fit/bridge.h b/pkg/fit/include/lib/fit/bridge.h
new file mode 100644
index 0000000..3fed908
--- /dev/null
+++ b/pkg/fit/include/lib/fit/bridge.h
@@ -0,0 +1,488 @@
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef LIB_FIT_BRIDGE_H_
+#define LIB_FIT_BRIDGE_H_
+
+#include "bridge_internal.h"
+
+namespace fit {
+
+// A bridge is a building block for asynchronous control flow that is formed
+// by the association of two distinct participants: a completer and a consumer.
+//
+// - The completer is responsible for reporting completion of an asynchronous
+//   task and providing its result.  See |completer()| and |fit::completer|.
+// - The consumer is responsible for consuming the result of the asynchronous
+//   task.  See |consumer()| and |fit::consumer|.
+//
+// This class is often used for binding a |fit::promise| to a callback,
+// facilitating interoperation of promises with functions that asynchronously
+// report their result via a callback function.  It can also be used more
+// generally anytime it is necessary to decouple completion of an asynchronous
+// task from consumption of its result (possibly on different threads).
+//
+// The completer and consumer each possesses a unique capability that can
+// be exercised at most once during their association: the asynchronous
+// task represented by a bridge can be completed at most once and its
+// result can be consumed at most once.  This property is enforced by
+// a single-ownership model for completers and consumers.
+//
+// The completion capability has a single owner represented by |fit::completer|.
+// Its owner may exercise the capability to complete the task (provide its result),
+// it may transfer the capability by moving it to another completer instance,
+// or it may cause the asynchronous task to be "abandoned" by discarding the
+// capability, implying that the task can never produce a result.  When this
+// occurs, the associated consumer's |fit::consumer::was_abandoned()| method
+// will return true and the consumer will not obtain any result from the task.
+// See |fit::consumer::promise()| and |fit::consumer::promise_or()| for
+// details on how abandonment of the task can be handled by the consumer.
+//
+// The consumption capability has a single owner represented by |fit::consumer|.
+// Its owner may exercise the capability to consume the task's result (as a
+/// promise), it may transfer the capability by moving it to another consumer
+// instance, or it may cause the asynchronous task to be "canceled" by
+// discarding the capability, implying that the task's result can never be
+// consumed.  When this occurs, the associated completer's
+// |fit::completer::was_canceled()| method will return true and the task's
+// eventual result (if any) will be silently discarded.
+//
+// DECOUPLING
+//
+// See |fit::schedule_for_consumer()| for a helper which uses a bridge to
+// decouple completion and consumption of a task's result so they can be
+// performed on different executors.
+//
+// SYNOPSIS
+//
+// |V| is the type of value produced when the task completes successfully.
+// Use |std::tuple<Args...>| if the task produces multiple values, such as
+// when you intend to bind the task's completer to a callback with multiple
+// arguments using |fit::completer::bind_tuple()|.
+// Defaults to |void|.
+//
+// |E| is the type of error produced when the task completes with an error.
+// Defaults to |void|.
+//
+// EXAMPLE
+//
+// Imagine a File I/O library offers a callback-based asynchronous reading
+// function.  We suppose that the read handling code will invoke the
+// callback upon completion.  The library's API might look a bit like this:
+//
+//     using read_callback = fit::function<void(size_t bytes_read)>;
+//     void read_async(size_t num_bytes, uint8_t* buffer, read_callback cb);
+//
+// Here's how we can adapt the library's "read_async" function to a
+// |fit::promise| by binding its callback to a bridge:
+//
+//     fit::promise<size_t> promise_read(uint8_t* buffer, size_t num_bytes) {
+//         fit::bridge<size_t> bridge;
+//         read_async(num_bytes, buffer, bridge.completer().bind());
+//         return bridge.consumer().promise_or(::fit::error());
+//     }
+//
+// Finally we can chain additional asynchronous tasks to be performed upon
+// completion of the promised read:
+//
+//     uint8_t buffer[4096];
+//     void my_program(fit::executor* executor) {
+//         auto promise = promise_read(buffer, sizeof(buffer))
+//             .and_then([] (size_t bytes_read) {
+//                 // consume contents of buffer
+//             })
+//             .or_else() {
+//                 // handle error case
+//             });
+//         executor->schedule_task(std::move(promise));
+//     }
+//
+// Similarly, suppose the File I/O library offers a callback-based asynchronous
+// writing function that can return a variety of errors encoded as negative
+// sizes.  Here's how we might decode those errors uniformly into |fit::result|
+// allowing them to be handled using combinators such as |or_else|.
+//
+//     using write_callback = fit::function<void(size_t bytes_written, int error)>;
+//     void write_async(size_t num_bytes, uint8_t* buffer, write_callback cb);
+//
+//     fit::promise<size_t, int> promise_write(uint8_t* buffer, size_t num_bytes) {
+//         fit::bridge<size_t, int> bridge;
+//         write_async(num_bytes, buffer,
+//             [completer = std::move(bridge.completer())](size_t bytes_written, int error) {
+//             if (bytes_written == 0) {
+//                 completer.complete_error(error);
+//                 return;
+//             }
+//             completer.complete_ok(bytes_written);
+//         });
+//         return bridge.consumer().promise_or(::fit::error(ERR_ABANDONED));
+//     }
+//
+//     uint8_t buffer[4096];
+//     void my_program(fit::executor* executor) {
+//         auto promise = promise_write(buffer, sizeof(buffer))
+//             .and_then([] (size_t bytes_written) {
+//                 // consume contents of buffer
+//             })
+//             .or_else(int error) {
+//                 // handle error case
+//             });
+//         executor->schedule_task(std::move(promise));
+//     }
+//
+// See documentation of |fit::promise| for more information.
+template <typename V, typename E>
+class bridge final {
+    using bridge_state = ::fit::internal::bridge_state<V, E>;
+
+public:
+    using value_type = V;
+    using error_type = E;
+    using result_type = result<value_type, error_type>;
+    using completer_type = ::fit::completer<V, E>;
+    using consumer_type = ::fit::consumer<V, E>;
+
+    // Creates a bridge representing a new asynchronous task formed by the
+    // association of a completer and consumer.
+    bridge() {
+        bridge_state::create(&completer_.completion_ref_,
+                             &consumer_.consumption_ref_);
+    }
+    bridge(bridge&& other) = default;
+    ~bridge() = default;
+
+    bridge& operator=(bridge&& other) = default;
+
+    // Gets a reference to the bridge's completer capability.
+    // The completer can be moved out of the bridge, if desired.
+    completer_type& completer() { return completer_; }
+    const completer_type& completer() const { return completer_; }
+
+    // Gets a reference to the bridge's consumer capability.
+    // The consumer can be moved out of the bridge, if desired.
+    consumer_type& consumer() { return consumer_; }
+    const consumer_type& consumer() const { return consumer_; }
+
+    bridge(const bridge& other) = delete;
+    bridge& operator=(const bridge& other) = delete;
+
+private:
+    completer_type completer_;
+    consumer_type consumer_;
+};
+
+// Provides a result upon completion of an asynchronous task.
+//
+// Instances of this class have single-ownership of a unique capability for
+// completing the task.  This capability can be exercised at most once.
+// Ownership of the capability is implicitly transferred away when the
+// completer is abandoned, completed, or bound to a callback.
+//
+// See also |fit::bridge|.
+// See documentation of |fit::promise| for more information.
+//
+// SYNOPSIS
+//
+// |V| is the type of value produced when the task completes successfully.
+// Use |std::tuple<Args...>| if the task produces multiple values, such as
+// when you intend to bind the task's completer to a callback with multiple
+// arguments using |fit::completer::bind_tuple()|.
+// Defaults to |void|.
+//
+// |E| is the type of error produced when the task completes with an error.
+// Defaults to |void|.
+template <typename V, typename E>
+class completer final {
+    using bridge_state = ::fit::internal::bridge_state<V, E>;
+    using completion_ref = typename bridge_state::completion_ref;
+
+public:
+    using value_type = V;
+    using error_type = E;
+    using result_type = ::fit::result<V, E>;
+
+    completer() = default;
+    completer(completer&& other) = default;
+    ~completer() = default;
+
+    completer& operator=(completer&& other) = default;
+
+    // Returns true if this instance currently owns the unique capability for
+    // reporting completion of the task.
+    explicit operator bool() const { return !!completion_ref_; }
+
+    // Returns true if the associated |consumer| has canceled the task.
+    // This method returns a snapshot of the current cancelation state.
+    // Note that the task may be canceled concurrently at any time.
+    bool was_canceled() const {
+        assert(completion_ref_);
+        return completion_ref_.get()->was_canceled();
+    }
+
+    // Explicitly abandons the task, meaning that it will never be completed.
+    // See |fit::bridge| for details about abandonment.
+    void abandon() {
+        assert(completion_ref_);
+        completion_ref_ = completion_ref();
+    }
+
+    // Reports that the task has completed successfully.
+    // This method takes no arguments if |value_type| is void, otherwise it
+    // takes one argument which must be assignable to |value_type|.
+    template <typename VV = value_type,
+              typename = std::enable_if_t<std::is_void<VV>::value>>
+    void complete_ok() {
+        assert(completion_ref_);
+        bridge_state* state = completion_ref_.get();
+        state->complete_or_abandon(std::move(completion_ref_),
+                                   ::fit::ok());
+    }
+    template <typename VV = value_type,
+              typename = std::enable_if_t<!std::is_void<VV>::value>>
+    void complete_ok(VV value) {
+        assert(completion_ref_);
+        bridge_state* state = completion_ref_.get();
+        state->complete_or_abandon(std::move(completion_ref_),
+                                   ::fit::ok<value_type>(std::forward<VV>(value)));
+    }
+
+    // Reports that the task has completed with an error.
+    // This method takes no arguments if |error_type| is void, otherwise it
+    // takes one argument which must be assignable to |error_type|.
+    template <typename EE = error_type,
+              typename = std::enable_if_t<std::is_void<EE>::value>>
+    void complete_error() {
+        assert(completion_ref_);
+        bridge_state* state = completion_ref_.get();
+        state->complete_or_abandon(std::move(completion_ref_),
+                                   ::fit::error());
+    }
+    template <typename EE = error_type,
+              typename = std::enable_if_t<!std::is_void<EE>::value>>
+    void complete_error(EE error) {
+        assert(completion_ref_);
+        bridge_state* state = completion_ref_.get();
+        state->complete_or_abandon(std::move(completion_ref_),
+                                   ::fit::error<error_type>(std::forward<EE>(error)));
+    }
+
+    // Reports that the task has completed or been abandoned.
+    // See |fit::bridge| for details about abandonment.
+    //
+    // The result state determines the task's final disposition.
+    // - |fit::result_state::ok|: The task completed successfully.
+    // - |fit::result_state::error|: The task completed with an error.
+    // - |fit::result_state::pending|: The task was abandoned.
+    void complete_or_abandon(result_type result) {
+        assert(completion_ref_);
+        bridge_state* state = completion_ref_.get();
+        state->complete_or_abandon(std::move(completion_ref_),
+                                   std::move(result));
+    }
+
+    // Returns a callback that reports completion of the asynchronous task along
+    // with its result when invoked.  This method is typically used to bind
+    // completion of a task to a callback that has zero or one argument.
+    //
+    // If |value_type| is void, the returned callback's signature is: void(void)
+    // Otherwise, the returned callback's signature is: void(value_type).
+    //
+    // The returned callback is thread-safe and move-only.
+    ::fit::internal::bridge_bind_callback<V, E> bind() {
+        assert(completion_ref_);
+        return ::fit::internal::bridge_bind_callback<V, E>(
+            std::move(completion_ref_));
+    }
+
+    // A variant of |bind()| that can be used to bind a completion of a task
+    // to a callback that has zero or more arguments by wrapping the callback's
+    // arguments into a tuple when producing the task's result.
+    //
+    // The |value_type| must be a tuple type.
+    // Given a |value_type| of std::tuple<Args...>, the returned callback's
+    // signature is: void(Args...).  Note that the tuple's fields are
+    // unpacked as individual arguments of the callback.
+    //
+    // The returned callback is thread-safe and move-only.
+    ::fit::internal::bridge_bind_tuple_callback<V, E> bind_tuple() {
+        assert(completion_ref_);
+        return ::fit::internal::bridge_bind_tuple_callback<V, E>(
+            std::move(completion_ref_));
+    }
+
+    completer(const completer& other) = delete;
+    completer& operator=(const completer& other) = delete;
+
+private:
+    friend class bridge<V, E>;
+
+    completion_ref completion_ref_;
+};
+
+// Consumes the result of an asynchronous task.
+//
+// Instances of this class have single-ownership of a unique capability for
+// consuming the task's result.  This capability can be exercised at most once.
+// Ownership of the capability is implicitly transferred away when the
+// task is canceled or converted to a promise.
+//
+// See also |fit::bridge|.
+// See documentation of |fit::promise| for more information.
+//
+// SYNOPSIS
+//
+// |V| is the type of value produced when the task completes successfully.
+// Use |std::tuple<Args...>| if the task produces multiple values, such as
+// when you intend to bind the task's completer to a callback with multiple
+// arguments using |fit::completer::bind_tuple()|.
+// Defaults to |void|.
+//
+// |E| is the type of error produced when the task completes with an error.
+// Defaults to |void|.
+template <typename V, typename E>
+class consumer final {
+    using bridge_state = ::fit::internal::bridge_state<V, E>;
+    using consumption_ref = typename bridge_state::consumption_ref;
+
+public:
+    using value_type = V;
+    using error_type = E;
+    using result_type = ::fit::result<V, E>;
+
+    consumer() = default;
+    consumer(consumer&& other) = default;
+    ~consumer() = default;
+
+    consumer& operator=(consumer&& other) = default;
+
+    // Returns true if this instance currently owns the unique capability for
+    // consuming the result of the task upon its completion.
+    explicit operator bool() const { return !!consumption_ref_; }
+
+    // Explicitly cancels the task, meaning that its result will never be consumed.
+    // See |fit::bridge| for details about cancelation.
+    void cancel() {
+        assert(consumption_ref_);
+        consumption_ref_ = consumption_ref();
+    }
+
+    // Returns true if the associated |completer| has abandoned the task.
+    // This method returns a snapshot of the current abandonment state.
+    // Note that the task may be abandoned concurrently at any time.
+    bool was_abandoned() const {
+        assert(consumption_ref_);
+        return consumption_ref_.get()->was_abandoned();
+    }
+
+    // Returns an unboxed promise which resumes execution once this task has
+    // completed.  If the task is abandoned by its completer, the promise
+    // will not produce a result, thereby causing subsequent tasks associated
+    // with the promise to also be abandoned and eventually destroyed if
+    // they cannot make progress without the promised result.
+    promise_impl<typename bridge_state::promise_continuation>
+    promise() {
+        assert(consumption_ref_);
+        return make_promise_with_continuation(
+            typename bridge_state::promise_continuation(
+                std::move(consumption_ref_)));
+    }
+
+    // A variant of |promise()| that allows a default result to be provided when
+    // the task is abandoned by its completer.  Typically this is used to cause
+    // the promise to return an error when the task is abandoned instead of
+    // causing subsequent tasks associated with the promise to also be abandoned.
+    //
+    // The state of |result_if_abandoned| determines the promise's behavior
+    // in case of abandonment.
+    //
+    // - |fit::result_state::ok|: Reports a successful result.
+    // - |fit::result_state::error|: Reports a failure result.
+    // - |fit::result_state::pending|: Does not report a result, thereby
+    //   causing subsequent tasks associated with the promise to also be
+    //   abandoned and eventually destroyed if they cannot make progress
+    //   without the promised result.
+    promise_impl<typename bridge_state::promise_continuation>
+    promise_or(result_type result_if_abandoned) {
+        assert(consumption_ref_);
+        return make_promise_with_continuation(
+            typename bridge_state::promise_continuation(
+                std::move(consumption_ref_), std::move(result_if_abandoned)));
+    }
+
+    consumer(const consumer& other) = delete;
+    consumer& operator=(const consumer& other) = delete;
+
+private:
+    friend class bridge<V, E>;
+
+    consumption_ref consumption_ref_;
+};
+
+// Schedules |promise| to run on |executor| and returns a |consumer| which
+// receives the result of the promise upon its completion.
+//
+// This method has the effect of decoupling the evaluation of a promise from
+// the consumption of its result such that they can be performed on different
+// executors (possibly on different threads).
+//
+// |executor| must be non-null.
+// |promise| must be non-empty.
+//
+// EXAMPLE
+//
+// This example shows an object that encapsulates its own executor which it
+// manages independently from that of its clients.  This enables the object
+// to obtain certain assurances such as a guarantee of single-threaded
+// execution for its internal operations even if its clients happen to be
+// multi-threaded (or vice-versa as desired).
+//
+//     // This model has specialized internal threading requirements so it
+//     // manages its own executor.
+//     class model {
+//     public:
+//         fit::consumer<int> perform_calculation(int parameter) {
+//             return fit::schedule_for_consumer(&executor_,
+//                 fit::make_promise([parameter] {
+//                     // In reality, this would likely be a much more
+//                     // complex expression.
+//                     return fit::ok(parameter * parameter);
+//                 });
+//         }
+//
+//     private:
+//         // The model is responsible for initializing and running its own
+//         // executor (perhaps on its own thread).
+//         fit::single_threaded_executor executor_;
+//     };
+//
+//     // Asks the model to perform a calculation, awaits a result on the
+//     // provided executor (which is different from the one internally used
+//     // by the model), then prints the result.
+//     void print_output(fit::executor* executor, model* m) {
+//         executor->schedule_task(
+//             m->perform_calculation(16)
+//                 .promise_or(fit::error())
+//                 .and_then([] (int result) { printf("done: %d\n", result); })
+//                 .or_else([] { puts("failed or abandoned"); }));
+//     }
+//
+template <typename Promise>
+inline consumer<typename Promise::value_type, typename Promise::error_type>
+schedule_for_consumer(fit::executor* executor, Promise promise) {
+    assert(executor);
+    assert(promise);
+    fit::bridge<typename Promise::value_type,
+                typename Promise::error_type>
+        bridge;
+    executor->schedule_task(
+        promise.then([completer = std::move(bridge.completer())](
+                         typename Promise::result_type& result) mutable {
+            completer.complete_or_abandon(std::move(result));
+        }));
+    return std::move(bridge.consumer());
+}
+
+} // namespace fit
+
+#endif // LIB_FIT_BRIDGE_H_
diff --git a/pkg/fit/include/lib/fit/bridge_internal.h b/pkg/fit/include/lib/fit/bridge_internal.h
new file mode 100644
index 0000000..8f805ee
--- /dev/null
+++ b/pkg/fit/include/lib/fit/bridge_internal.h
@@ -0,0 +1,401 @@
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef LIB_FIT_BRIDGE_INTERNAL_H_
+#define LIB_FIT_BRIDGE_INTERNAL_H_
+
+#include <atomic>
+#include <mutex>
+#include <tuple>
+#include <type_traits>
+#include <utility>
+
+#include "promise.h"
+#include "result.h"
+#include "thread_safety.h"
+
+namespace fit {
+namespace internal {
+
+// State shared between one completer and one consumer.
+// This object is somewhat unusual in that it has dual-ownership represented
+// by a pair of single-ownership references: a |completion_ref| and a
+// |consumption_ref|.
+//
+// The bridge's state evolves as follows:
+// - Initially the bridge's disposition is "pending".
+// - When the completer produces a result, the bridge's disposition
+//   becomes "completed".
+// - When the completer drops its ref without producing a result,
+//   the bridge's disposition becomes "abandoned".
+// - When the consumer drops its ref without consuming the result,
+//   the bridge's disposition becomes "canceled".
+// - When a full rendezvous between completer and consumer takes place,
+//   the bridge's disposition becomes "returned".
+// - When both refs are dropped, the bridge state is destroyed.
+template <typename V, typename E>
+class bridge_state final {
+public:
+    class completion_ref;
+    class consumption_ref;
+    class promise_continuation;
+
+    using result_type = result<V, E>;
+
+    ~bridge_state() = default;
+
+    static void create(completion_ref* out_completion_ref,
+                       consumption_ref* out_consumption_ref);
+
+    bool was_canceled() const;
+    bool was_abandoned() const;
+    void complete_or_abandon(completion_ref ref, result_type result);
+
+    bridge_state(const bridge_state&) = delete;
+    bridge_state(bridge_state&&) = delete;
+    bridge_state& operator=(const bridge_state&) = delete;
+    bridge_state& operator=(bridge_state&&) = delete;
+
+private:
+    enum class disposition {
+        pending,
+        abandoned,
+        completed,
+        canceled,
+        returned
+    };
+
+    bridge_state() = default;
+
+    void drop_completion_ref(bool was_completed);
+    void drop_consumption_ref(bool was_consumed);
+    void drop_ref_and_maybe_delete_self();
+    void set_result_if_abandoned(result_type result_if_abandoned);
+    result_type await_result(consumption_ref* ref, ::fit::context& context);
+    void deliver_result() FIT_REQUIRES(mutex_);
+
+    mutable std::mutex mutex_;
+
+    // Ref-count for completion and consumption.
+    // There can only be one of each ref type so the initial count is 2.
+    std::atomic<uint32_t> ref_count_{2};
+
+    // The disposition of the bridge.
+    disposition disposition_ FIT_GUARDED(mutex_) = {disposition::pending};
+
+    // The suspended task.
+    // Invariant: Only valid when disposition is |pending|.
+    suspended_task task_ FIT_GUARDED(mutex_);
+
+    // The result in flight.
+    // Invariant: Only valid when disposition is |pending|, |completed|,
+    // or |abandoned|.
+    result_type result_ FIT_GUARDED(mutex_);
+};
+
+// The unique capability held by a bridge's completer.
+template <typename V, typename E>
+class bridge_state<V, E>::completion_ref final {
+public:
+    completion_ref()
+        : state_(nullptr) {}
+
+    explicit completion_ref(bridge_state* state)
+        : state_(state) {} // adopts existing reference
+
+    completion_ref(completion_ref&& other)
+        : state_(other.state_) {
+        other.state_ = nullptr;
+    }
+
+    ~completion_ref() {
+        if (state_)
+            state_->drop_completion_ref(false /*was_completed*/);
+    }
+
+    completion_ref& operator=(completion_ref&& other) {
+        if (&other == this)
+            return *this;
+        if (state_)
+            state_->drop_completion_ref(false /*was_completed*/);
+        state_ = other.state_;
+        other.state_ = nullptr;
+        return *this;
+    }
+
+    explicit operator bool() const { return !!state_; }
+
+    bridge_state* get() const { return state_; }
+
+    void drop_after_completion() {
+        state_->drop_completion_ref(true /*was_completed*/);
+        state_ = nullptr;
+    }
+
+    completion_ref(const completion_ref& other) = delete;
+    completion_ref& operator=(const completion_ref& other) = delete;
+
+private:
+    bridge_state* state_;
+};
+
+// The unique capability held by a bridge's consumer.
+template <typename V, typename E>
+class bridge_state<V, E>::consumption_ref final {
+public:
+    consumption_ref()
+        : state_(nullptr) {}
+
+    explicit consumption_ref(bridge_state* state)
+        : state_(state) {} // adopts existing reference
+
+    consumption_ref(consumption_ref&& other)
+        : state_(other.state_) {
+        other.state_ = nullptr;
+    }
+
+    ~consumption_ref() {
+        if (state_)
+            state_->drop_consumption_ref(false /*was_consumed*/);
+    }
+
+    consumption_ref& operator=(consumption_ref&& other) {
+        if (&other == this)
+            return *this;
+        if (state_)
+            state_->drop_consumption_ref(false /*was_consumed*/);
+        state_ = other.state_;
+        other.state_ = nullptr;
+        return *this;
+    }
+
+    explicit operator bool() const { return !!state_; }
+
+    bridge_state* get() const { return state_; }
+
+    void drop_after_consumption() {
+        state_->drop_consumption_ref(true /*was_consumed*/);
+        state_ = nullptr;
+    }
+
+    consumption_ref(const consumption_ref& other) = delete;
+    consumption_ref& operator=(const consumption_ref& other) = delete;
+
+private:
+    bridge_state* state_;
+};
+
+// The continuation produced by |consumer::promise()| and company.
+template <typename V, typename E>
+class bridge_state<V, E>::promise_continuation final {
+public:
+    explicit promise_continuation(consumption_ref ref)
+        : ref_(std::move(ref)) {}
+
+    promise_continuation(consumption_ref ref,
+                         result_type result_if_abandoned)
+        : ref_(std::move(ref)) {
+        ref_.get()->set_result_if_abandoned(std::move(result_if_abandoned));
+    }
+
+    result_type operator()(::fit::context& context) {
+        return ref_.get()->await_result(&ref_, context);
+    }
+
+private:
+    consumption_ref ref_;
+};
+
+// The callback produced by |completer::bind()|.
+template <typename V, typename E>
+class bridge_bind_callback final {
+    using bridge_state = bridge_state<V, E>;
+
+public:
+    explicit bridge_bind_callback(typename bridge_state::completion_ref ref)
+        : ref_(std::move(ref)) {}
+
+    template <typename VV = V,
+              typename = std::enable_if_t<std::is_void<VV>::value>>
+    void operator()() {
+        bridge_state* state = ref_.get();
+        state->complete_or_abandon(std::move(ref_), ::fit::ok());
+    }
+
+    template <typename VV = V,
+              typename = std::enable_if_t<!std::is_void<VV>::value>>
+    void operator()(VV value) {
+        bridge_state* state = ref_.get();
+        state->complete_or_abandon(std::move(ref_),
+                                   ::fit::ok<V>(std::forward<VV>(value)));
+    }
+
+private:
+    typename bridge_state::completion_ref ref_;
+};
+
+// The callback produced by |completer::bind_tuple()|.
+template <typename V, typename E>
+class bridge_bind_tuple_callback;
+template <typename... Args, typename E>
+class bridge_bind_tuple_callback<std::tuple<Args...>, E> final {
+    using bridge_state = bridge_state<std::tuple<Args...>, E>;
+
+public:
+    explicit bridge_bind_tuple_callback(typename bridge_state::completion_ref ref)
+        : ref_(std::move(ref)) {}
+
+    void operator()(Args... args) {
+        bridge_state* state = ref_.get();
+        state->complete_or_abandon(
+            std::move(ref_),
+            ::fit::ok(std::make_tuple<Args...>(std::forward<Args>(args)...)));
+    }
+
+private:
+    typename bridge_state::completion_ref ref_;
+};
+
+template <typename V, typename E>
+void bridge_state<V, E>::create(completion_ref* out_completion_ref,
+                                consumption_ref* out_consumption_ref) {
+    bridge_state* state = new bridge_state();
+    *out_completion_ref = completion_ref(state);
+    *out_consumption_ref = consumption_ref(state);
+}
+
+template <typename V, typename E>
+bool bridge_state<V, E>::was_canceled() const {
+    std::lock_guard<std::mutex> lock(mutex_);
+    return disposition_ == disposition::canceled;
+}
+
+template <typename V, typename E>
+bool bridge_state<V, E>::was_abandoned() const {
+    std::lock_guard<std::mutex> lock(mutex_);
+    return disposition_ == disposition::abandoned;
+}
+
+template <typename V, typename E>
+void bridge_state<V, E>::drop_completion_ref(bool was_completed) {
+    if (!was_completed) {
+        // The task was abandoned.
+        std::lock_guard<std::mutex> lock(mutex_);
+        assert(disposition_ == disposition::pending ||
+               disposition_ == disposition::canceled);
+        if (disposition_ == disposition::pending) {
+            disposition_ = disposition::abandoned;
+            deliver_result();
+        }
+    }
+    drop_ref_and_maybe_delete_self();
+}
+
+template <typename V, typename E>
+void bridge_state<V, E>::drop_consumption_ref(bool was_consumed) {
+    if (!was_consumed) {
+        // The task was canceled.
+        std::lock_guard<std::mutex> lock(mutex_);
+        assert(disposition_ == disposition::pending ||
+               disposition_ == disposition::completed ||
+               disposition_ == disposition::abandoned);
+        if (disposition_ == disposition::pending) {
+            disposition_ = disposition::canceled;
+            result_ = ::fit::pending();
+            task_.reset(); // there is no task to wake up anymore
+        }
+    }
+    drop_ref_and_maybe_delete_self();
+}
+
+template <typename V, typename E>
+void bridge_state<V, E>::drop_ref_and_maybe_delete_self() {
+    uint32_t count = ref_count_.fetch_sub(1u, std::memory_order_release) - 1u;
+    assert(count >= 0);
+    if (count == 0) {
+        std::atomic_thread_fence(std::memory_order_acquire);
+        delete this;
+    }
+}
+
+template <typename V, typename E>
+void bridge_state<V, E>::complete_or_abandon(completion_ref ref,
+                                             result_type result) {
+    assert(ref.get() == this);
+    if (result.is_pending())
+        return; // let the ref go out of scope to abandon the task
+
+    {
+        std::lock_guard<std::mutex> lock(mutex_);
+        assert(disposition_ == disposition::pending ||
+               disposition_ == disposition::canceled);
+        if (disposition_ == disposition::pending) {
+            disposition_ = disposition::completed;
+            result_ = std::move(result);
+            deliver_result();
+        }
+    }
+    // drop the reference ouside of the lock
+    ref.drop_after_completion();
+}
+
+template <typename V, typename E>
+void bridge_state<V, E>::set_result_if_abandoned(
+    result_type result_if_abandoned) {
+    if (result_if_abandoned.is_pending())
+        return; // nothing to do
+
+    std::lock_guard<std::mutex> lock(mutex_);
+    assert(disposition_ == disposition::pending ||
+           disposition_ == disposition::completed ||
+           disposition_ == disposition::abandoned);
+    if (disposition_ == disposition::pending ||
+        disposition_ == disposition::abandoned) {
+        result_ = std::move(result_if_abandoned);
+    }
+}
+
+template <typename V, typename E>
+typename bridge_state<V, E>::result_type bridge_state<V, E>::await_result(
+    consumption_ref* ref, ::fit::context& context) {
+    assert(ref->get() == this);
+    result_type result;
+    {
+        std::lock_guard<std::mutex> lock(mutex_);
+        assert(disposition_ == disposition::pending ||
+               disposition_ == disposition::completed ||
+               disposition_ == disposition::abandoned);
+        if (disposition_ == disposition::pending) {
+            task_ = context.suspend_task();
+            return ::fit::pending();
+        }
+        disposition_ = disposition::returned;
+        result = std::move(result_);
+    }
+    // drop the reference ouside of the lock
+    ref->drop_after_consumption();
+    return result;
+}
+
+template <typename V, typename E>
+void bridge_state<V, E>::deliver_result() {
+    if (result_.is_pending()) {
+        task_.reset(); // the task has been canceled
+    } else {
+        task_.resume_task(); // we have a result so wake up the task
+    }
+}
+
+} // namespace internal
+
+template <typename V = void, typename E = void>
+class bridge;
+template <typename V = void, typename E = void>
+class completer;
+template <typename V = void, typename E = void>
+class consumer;
+
+} // namespace fit
+
+#endif // LIB_FIT_BRIDGE_INTERNAL_H_
diff --git a/pkg/fit/include/lib/fit/defer.h b/pkg/fit/include/lib/fit/defer.h
new file mode 100644
index 0000000..7d85048
--- /dev/null
+++ b/pkg/fit/include/lib/fit/defer.h
@@ -0,0 +1,138 @@
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef LIB_FIT_DEFER_H_
+#define LIB_FIT_DEFER_H_
+
+#include <utility>
+
+#include "nullable.h"
+
+namespace fit {
+
+// A move-only deferred action wrapper with RAII semantics.
+// This class is not thread safe.
+//
+// The wrapper holds a function-like callable target with no arguments
+// which it invokes when it goes out of scope unless canceled, called, or
+// moved to a wrapper in a different scope.
+//
+// See |fit::defer()| for idiomatic usage.
+template <typename T>
+class deferred_action final {
+public:
+    // Creates a deferred action without a pending target.
+    deferred_action() = default;
+    explicit deferred_action(decltype(nullptr)) {}
+
+    // Creates a deferred action with a pending target.
+    explicit deferred_action(T target)
+        : target_(std::move(target)) {}
+
+    // Creates a deferred action with a pending target moved from another
+    // deferred action, leaving the other one without a pending target.
+    deferred_action(deferred_action&& other) = default;
+
+    // Invokes and releases the deferred action's pending target (if any).
+    ~deferred_action() {
+        call();
+    }
+
+    // Returns true if the deferred action has a pending target.
+    explicit operator bool() const {
+        return !!target_;
+    }
+
+    // Invokes and releases the deferred action's pending target (if any),
+    // then move-assigns it from another deferred action, leaving the latter
+    // one without a pending target.
+    deferred_action& operator=(deferred_action&& other) {
+        if (&other == this)
+            return *this;
+        call();
+        target_ = std::move(other.target_);
+        return *this;
+    }
+
+    // Invokes and releases the deferred action's pending target (if any).
+    void call() {
+        if (target_) {
+            // Move to a local to guard against re-entrance.
+            T local_target = std::move(*target_);
+            target_.reset();
+            local_target();
+        }
+    }
+
+    // Releases the deferred action's pending target (if any) without
+    // invoking it.
+    void cancel() {
+        target_.reset();
+    }
+    deferred_action& operator=(decltype(nullptr)) {
+        cancel();
+        return *this;
+    }
+
+    // Assigns a new target to the deferred action.
+    deferred_action& operator=(T target) {
+        target_ = std::move(target);
+        return *this;
+    }
+
+    deferred_action(const deferred_action& other) = delete;
+    deferred_action& operator=(const deferred_action& other) = delete;
+
+private:
+    nullable<T> target_;
+};
+
+template <typename T>
+bool operator==(const deferred_action<T>& action, decltype(nullptr)) {
+    return !action;
+}
+template <typename T>
+bool operator==(decltype(nullptr), const deferred_action<T>& action) {
+    return !action;
+}
+template <typename T>
+bool operator!=(const deferred_action<T>& action, decltype(nullptr)) {
+    return !!action;
+}
+template <typename T>
+bool operator!=(decltype(nullptr), const deferred_action<T>& action) {
+    return !!action;
+}
+
+// Defers execution of a function-like callable target with no arguments
+// until the value returned by this function goes out of scope unless canceled,
+// called, or moved to a wrapper in a different scope.
+//
+// // This example prints "Hello..." then "Goodbye!".
+// void test() {
+//     auto d = fit::defer([]{ puts("Goodbye!"); });
+//     puts("Hello...");
+// }
+//
+// // This example prints nothing because the deferred action is canceled.
+// void do_nothing() {
+//     auto d = fit::defer([]{ puts("I'm not here."); });
+//     d.cancel();
+// }
+//
+// // This example shows how the deferred action can be reassigned assuming
+// // the new target has the same type and the old one, in this case by
+// // representing the target as a |fit::closure|.
+// void reassign() {
+//     auto d = fit::defer<fit::closure>([] { puts("This runs first."); });
+//     d = fit::defer<fit::closure>([] { puts("This runs afterwards."); });
+// }
+template <typename T>
+inline deferred_action<T> defer(T target) {
+    return deferred_action<T>(std::move(target));
+}
+
+} // namespace fit
+
+#endif // LIB_FIT_DEFER_H_
diff --git a/pkg/fit/include/lib/fit/function.h b/pkg/fit/include/lib/fit/function.h
new file mode 100644
index 0000000..5aaecca
--- /dev/null
+++ b/pkg/fit/include/lib/fit/function.h
@@ -0,0 +1,315 @@
+// Copyright 2017 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef LIB_FIT_FUNCTION_H_
+#define LIB_FIT_FUNCTION_H_
+
+#include <memory>
+#include <type_traits>
+
+#include "function_internal.h"
+#include "nullable.h"
+
+namespace fit {
+
+template <size_t inline_target_size, bool require_inline,
+          typename Result, typename... Args>
+class function_impl;
+
+// The default size allowance for storing a target inline within a function
+// object, in bytes.  This default allows for inline storage of targets
+// as big as two pointers, such as an object pointer and a pointer to a member
+// function.
+constexpr size_t default_inline_target_size = sizeof(void*) * 2;
+
+// A |fit::function| is a move-only polymorphic function wrapper.
+//
+// |fit::function<T>| behaves like |std::function<T>| except that it is move-only
+// instead of copyable so it can hold targets which cannot be copied, such as
+// mutable lambdas.
+//
+// Targets of up to |inline_target_size| bytes in size (rounded up for memory
+// alignment) are stored inline within the function object without incurring
+// any heap allocation.  Larger callable objects will be moved to the heap as
+// required.
+//
+// See also |fit::inline_function<T, size>| for more control over allocation
+// behavior.
+//
+// SYNOPSIS
+//
+// |T| is the function's signature.  e.g. void(int, std::string).
+//
+// |inline_target_size| is the minimum size of target that is guaranteed to
+// fit within a function without requiring heap allocation.
+// Defaults to |default_inline_target_size|.
+//
+// Class members are documented in |fit::function_impl|.
+//
+// EXAMPLES
+//
+// - https://fuchsia.googlesource.com/zircon/+/master/system/utest/fit/examples/function_example1.cpp
+// - https://fuchsia.googlesource.com/zircon/+/master/system/utest/fit/examples/function_example2.cpp
+//
+template <typename T, size_t inline_target_size = default_inline_target_size>
+using function = function_impl<inline_target_size, false, T>;
+
+// A move-only callable object wrapper which forces callables to be stored inline
+// and never performs heap allocation.
+//
+// Behaves just like |fit::function<T, inline_target_size>| except that attempting
+// to store a target larger than |inline_target_size| will fail to compile.
+template <typename T, size_t inline_target_size = default_inline_target_size>
+using inline_function = function_impl<inline_target_size, true, T>;
+
+// Synonym for a function which takes no arguments and produces no result.
+using closure = function<void()>;
+
+// Function implementation details.
+// See |fit::function| documentation for more information.
+template <size_t inline_target_size, bool require_inline,
+          typename Result, typename... Args>
+class function_impl<inline_target_size, require_inline, Result(Args...)> final {
+    using ops_type = const ::fit::internal::target_ops<Result, Args...>*;
+    using storage_type = typename std::aligned_storage<
+        (inline_target_size >= sizeof(void*)
+             ? inline_target_size
+             : sizeof(void*))>::type; // avoid including <algorithm> just for max
+    template <typename Callable>
+    using target_type = ::fit::internal::target<
+        Callable,
+        (sizeof(Callable) <= sizeof(storage_type)),
+        Result, Args...>;
+    using null_target_type = target_type<decltype(nullptr)>;
+
+public:
+    // The function's result type.
+    using result_type = Result;
+
+    // // Creates a function with an empty target.
+    function_impl() {
+        initialize_null_target();
+    }
+
+    // Creates a function with an empty target.
+    function_impl(decltype(nullptr)) {
+        initialize_null_target();
+    }
+
+    // Creates a function bound to the specified function pointer.
+    // If target == nullptr, assigns an empty target.
+    function_impl(Result (*target)(Args...)) {
+        initialize_target(target);
+    }
+
+    // Creates a function bound to the specified callable object.
+    // If target == nullptr, assigns an empty target.
+    //
+    // For functors, we need to capture the raw type but also restrict on the existence of an
+    // appropriate operator () to resolve overloads and implicit casts properly.
+    template <typename Callable,
+              typename = std::enable_if_t<
+                  std::is_convertible<
+                      decltype(std::declval<Callable&>()(
+                          std::declval<Args>()...)),
+                      result_type>::value>>
+    function_impl(Callable target) {
+        initialize_target(std::move(target));
+    }
+
+    // Creates a function with a target moved from another function,
+    // leaving the other function with an empty target.
+    function_impl(function_impl&& other) {
+        move_target_from(std::move(other));
+    }
+
+    // Destroys the function, releasing its target.
+    ~function_impl() {
+        destroy_target();
+    }
+
+    // Returns true if the function has a non-empty target.
+    explicit operator bool() const {
+        return ops_ != &null_target_type::ops;
+    };
+
+    // Invokes the function's target.
+    // Aborts if the function's target is empty.
+    Result operator()(Args... args) const {
+        return ops_->invoke(&bits_, std::forward<Args>(args)...);
+    }
+
+    // Assigns an empty target.
+    function_impl& operator=(decltype(nullptr)) {
+        destroy_target();
+        initialize_null_target();
+        return *this;
+    }
+
+    // Assigns the function's target.
+    // If target == nullptr, assigns an empty target.
+    template <typename Callable,
+              typename = std::enable_if_t<
+                  std::is_convertible<
+                      decltype(std::declval<Callable&>()(
+                          std::declval<Args>()...)),
+                      result_type>::value>>
+    function_impl& operator=(Callable target) {
+        destroy_target();
+        initialize_target(std::move(target));
+        return *this;
+    }
+
+    // Assigns the function with a target moved from another function,
+    // leaving the other function with an empty target.
+    function_impl& operator=(function_impl&& other) {
+        if (&other == this)
+            return *this;
+        destroy_target();
+        move_target_from(std::move(other));
+        return *this;
+    }
+
+    // Swaps the functions' targets.
+    void swap(function_impl& other) {
+        if (&other == this)
+            return;
+        ops_type temp_ops = ops_;
+        storage_type temp_bits;
+        ops_->move(&bits_, &temp_bits);
+
+        ops_ = other.ops_;
+        other.ops_->move(&other.bits_, &bits_);
+
+        other.ops_ = temp_ops;
+        temp_ops->move(&temp_bits, &other.bits_);
+    }
+
+    // Returns a pointer to the function's target.
+    template <typename Callable>
+    Callable* target() {
+        check_target_type<Callable>();
+        return static_cast<Callable*>(ops_->get(&bits_));
+    }
+
+    // Returns a pointer to the function's target.
+    template <typename Callable>
+    const Callable* target() const {
+        check_target_type<Callable>();
+        return static_cast<Callable*>(ops_->get(&bits_));
+    }
+
+    // Returns a new function object which invokes the same target.
+    // The target itself is not copied; it is moved to the heap and its
+    // lifetime is extended until all references have been released.
+    //
+    // Note: This method is not supported on |fit::inline_function<>|
+    //       because it may incur a heap allocation which is contrary to
+    //       the stated purpose of |fit::inline_function<>|.
+    function_impl share() {
+        static_assert(!require_inline, "Inline functions cannot be shared.");
+        // TODO(jeffbrown): Replace shared_ptr with a better ref-count mechanism.
+        // TODO(jeffbrown): This definition breaks the client's ability to use
+        // |target()| because the target's type has changed.  We could fix this
+        // by defining a new target type (and vtable) for shared targets
+        // although it would be nice to avoid memory overhead and code expansion
+        // when sharing is not used.
+        struct ref {
+            std::shared_ptr<function_impl> target;
+            Result operator()(Args... args) {
+                return (*target)(std::forward<Args>(args)...);
+            }
+        };
+        if (ops_ != &target_type<ref>::ops) {
+            if (ops_ == &null_target_type::ops) {
+                return nullptr;
+            }
+            auto target = ref{std::make_shared<function_impl>(std::move(*this))};
+            *this = std::move(target);
+        }
+        return function_impl(*static_cast<ref*>(ops_->get(&bits_)));
+    }
+
+    function_impl(const function_impl& other) = delete;
+    function_impl& operator=(const function_impl& other) = delete;
+
+private:
+    // assumes target is uninitialized
+    void initialize_null_target() {
+        ops_ = &null_target_type::ops;
+    }
+
+    // assumes target is uninitialized
+    template <typename Callable>
+    void initialize_target(Callable target) {
+        static_assert(!require_inline || sizeof(Callable) <= inline_target_size,
+                      "Callable too large to store inline as requested.");
+        if (is_null(target)) {
+            initialize_null_target();
+        } else {
+            ops_ = &target_type<Callable>::ops;
+            target_type<Callable>::initialize(&bits_, std::move(target));
+        }
+    }
+
+    // leaves target uninitialized
+    void destroy_target() {
+        ops_->destroy(&bits_);
+    }
+
+    // leaves other target initialized to null
+    void move_target_from(function_impl&& other) {
+        ops_ = other.ops_;
+        other.ops_->move(&other.bits_, &bits_);
+        other.initialize_null_target();
+    }
+
+    template <typename Callable>
+    void check_target_type() const {
+        if (ops_ != &target_type<Callable>::ops)
+            abort();
+    }
+
+    ops_type ops_;
+    mutable storage_type bits_;
+}; // namespace fit
+
+template <size_t inline_target_size, bool require_inline, typename Result, typename... Args>
+void swap(function_impl<inline_target_size, require_inline, Result, Args...>& a,
+          function_impl<inline_target_size, require_inline, Result, Args...>& b) {
+    a.swap(b);
+}
+
+template <size_t inline_target_size, bool require_inline, typename Result, typename... Args>
+bool operator==(const function_impl<inline_target_size, require_inline, Result, Args...>& f,
+                decltype(nullptr)) {
+    return !f;
+}
+template <size_t inline_target_size, bool require_inline, typename Result, typename... Args>
+bool operator==(decltype(nullptr),
+                const function_impl<inline_target_size, require_inline, Result, Args...>& f) {
+    return !f;
+}
+template <size_t inline_target_size, bool require_inline, typename Result, typename... Args>
+bool operator!=(const function_impl<inline_target_size, require_inline, Result, Args...>& f,
+                decltype(nullptr)) {
+    return !!f;
+}
+template <size_t inline_target_size, bool require_inline, typename Result, typename... Args>
+bool operator!=(decltype(nullptr),
+                const function_impl<inline_target_size, require_inline, Result, Args...>& f) {
+    return !!f;
+}
+
+// Returns a Callable object which invokes a member function of an object.
+template <typename R, typename T, typename... Args>
+auto bind_member(T* instance, R (T::*fn)(Args...)) {
+    return [instance, fn](Args... args) {
+        return (instance->*fn)(std::forward<Args>(args)...);
+    };
+}
+
+} // namespace fit
+
+#endif // LIB_FIT_FUNCTION_H_
diff --git a/pkg/fit/include/lib/fit/function_internal.h b/pkg/fit/include/lib/fit/function_internal.h
new file mode 100644
index 0000000..ddcefef
--- /dev/null
+++ b/pkg/fit/include/lib/fit/function_internal.h
@@ -0,0 +1,121 @@
+// Copyright 2017 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef LIB_FIT_FUNCTION_INTERNAL_H_
+#define LIB_FIT_FUNCTION_INTERNAL_H_
+
+#include <stddef.h>
+#include <stdlib.h>
+
+#include <new>
+#include <type_traits>
+#include <utility>
+
+namespace fit {
+namespace internal {
+
+template <typename Result, typename... Args>
+struct target_ops final {
+    void* (*get)(void* bits);
+    Result (*invoke)(void* bits, Args... args);
+    void (*move)(void* from_bits, void* to_bits);
+    void (*destroy)(void* bits);
+};
+
+template <typename Callable, bool is_inline, typename Result, typename... Args>
+struct target;
+
+template <typename Result, typename... Args>
+struct target<decltype(nullptr), true, Result, Args...> final {
+    static Result invoke(void* bits, Args... args) {
+        abort();
+    }
+
+    static const target_ops<Result, Args...> ops;
+};
+
+inline void* null_target_get(void* bits) {
+    return nullptr;
+}
+inline void null_target_move(void* from_bits, void* to_bits) {}
+inline void null_target_destroy(void* bits) {}
+
+template <typename Result, typename... Args>
+constexpr target_ops<Result, Args...> target<decltype(nullptr), true, Result, Args...>::ops = {
+    &null_target_get,
+    &target::invoke,
+    &null_target_move,
+    &null_target_destroy};
+
+template <typename Callable, typename Result, typename... Args>
+struct target<Callable, true, Result, Args...> final {
+    static void initialize(void* bits, Callable&& target) {
+        new (bits) Callable(std::move(target));
+    }
+    static Result invoke(void* bits, Args... args) {
+        auto& target = *static_cast<Callable*>(bits);
+        return target(std::forward<Args>(args)...);
+    }
+    static void move(void* from_bits, void* to_bits) {
+        auto& from_target = *static_cast<Callable*>(from_bits);
+        new (to_bits) Callable(std::move(from_target));
+        from_target.~Callable();
+    }
+    static void destroy(void* bits) {
+        auto& target = *static_cast<Callable*>(bits);
+        target.~Callable();
+    }
+
+    static const target_ops<Result, Args...> ops;
+};
+
+inline void* inline_target_get(void* bits) {
+    return bits;
+}
+
+template <typename Callable, typename Result, typename... Args>
+constexpr target_ops<Result, Args...> target<Callable, true, Result, Args...>::ops = {
+    &inline_target_get,
+    &target::invoke,
+    &target::move,
+    &target::destroy};
+
+template <typename Callable, typename Result, typename... Args>
+struct target<Callable, false, Result, Args...> final {
+    static void initialize(void* bits, Callable&& target) {
+        auto ptr = static_cast<Callable**>(bits);
+        *ptr = new Callable(std::move(target));
+    }
+    static Result invoke(void* bits, Args... args) {
+        auto& target = **static_cast<Callable**>(bits);
+        return target(std::forward<Args>(args)...);
+    }
+    static void move(void* from_bits, void* to_bits) {
+        auto from_ptr = static_cast<Callable**>(from_bits);
+        auto to_ptr = static_cast<Callable**>(to_bits);
+        *to_ptr = *from_ptr;
+    }
+    static void destroy(void* bits) {
+        auto ptr = static_cast<Callable**>(bits);
+        delete *ptr;
+    }
+
+    static const target_ops<Result, Args...> ops;
+};
+
+inline void* heap_target_get(void* bits) {
+    return *static_cast<void**>(bits);
+}
+
+template <typename Callable, typename Result, typename... Args>
+constexpr target_ops<Result, Args...> target<Callable, false, Result, Args...>::ops = {
+    &heap_target_get,
+    &target::invoke,
+    &target::move,
+    &target::destroy};
+
+} // namespace internal
+} // namespace fit
+
+#endif // LIB_FIT_FUNCTION_INTERNAL_H_
diff --git a/pkg/fit/include/lib/fit/function_traits.h b/pkg/fit/include/lib/fit/function_traits.h
new file mode 100644
index 0000000..3e0c2a3
--- /dev/null
+++ b/pkg/fit/include/lib/fit/function_traits.h
@@ -0,0 +1,18 @@
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef LIB_FIT_FUNCTION_TRAITS_H_
+#define LIB_FIT_FUNCTION_TRAITS_H_
+
+#include "traits.h"
+
+namespace fit {
+
+// function_traits is deprecated, please use callable_traits
+template <typename T>
+using function_traits = callable_traits<T>;
+
+} // namespace fit
+
+#endif // LIB_FIT_FUNCTION_TRAITS_H_
diff --git a/pkg/fit/include/lib/fit/nullable.h b/pkg/fit/include/lib/fit/nullable.h
new file mode 100644
index 0000000..a6050af
--- /dev/null
+++ b/pkg/fit/include/lib/fit/nullable.h
@@ -0,0 +1,245 @@
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef LIB_FIT_NULLABLE_H_
+#define LIB_FIT_NULLABLE_H_
+
+#include <assert.h>
+
+#include <type_traits>
+#include <utility>
+
+#include "optional.h"
+
+namespace fit {
+
+// Determines whether a type can be compared with nullptr.
+template <typename T, typename Comparable = bool>
+struct is_comparable_with_null : public std::false_type {};
+template <typename T>
+struct is_comparable_with_null<T, decltype(std::declval<const T&>() == nullptr)>
+    : public std::true_type {};
+
+// Returns true if a value equals nullptr.
+template <typename T, typename Comparable = bool>
+struct is_null_predicate {
+    constexpr bool operator()(const T& value) { return false; }
+};
+template <typename T>
+struct is_null_predicate<T, decltype(std::declval<const T&>() == nullptr)> {
+    constexpr bool operator()(const T& value) { return value == nullptr; }
+};
+template <typename T>
+constexpr inline bool is_null(const T& value) {
+    return is_null_predicate<T>()(value);
+}
+
+// Determines whether a type can be initialized, assigned, and compared
+// with nullptr.
+template <typename T>
+struct is_nullable
+    : public std::integral_constant<
+          bool,
+          std::is_constructible<T, decltype(nullptr)>::value &&
+              std::is_assignable<T&, decltype(nullptr)>::value &&
+              is_comparable_with_null<T>::value> {};
+template <>
+struct is_nullable<void> : public std::false_type {};
+
+// Holds a value or nullptr.
+//
+// This class is similar to |std::optional<T>| except that it uses less
+// storage when the value type can be initialized, assigned, and compared
+// with nullptr.
+//
+// For example:
+// - sizeof(fit::nullable<void*>) == sizeof(void*)
+// - sizeof(std::optional<void*>) == sizeof(struct { bool; void*; })
+// - sizeof(fit::nullable<int>) == sizeof(struct { bool; int; })
+// - sizeof(std::optional<int>) == sizeof(struct { bool; int; })
+template <typename T, bool = (is_nullable<T>::value &&
+                              std::is_constructible<T, T&&>::value &&
+                              std::is_assignable<T&, T&&>::value)>
+class nullable final {
+public:
+    using value_type = T;
+
+    constexpr nullable() = default;
+    explicit constexpr nullable(decltype(nullptr)) {}
+    explicit constexpr nullable(T value)
+        : opt_(std::move(value)) {}
+    nullable(const nullable& other) = default;
+    nullable(nullable&& other) = default;
+    ~nullable() = default;
+
+    constexpr T& value() & { return opt_.value(); }
+    constexpr const T& value() const& { return opt_.value(); }
+    constexpr T&& value() && { return std::move(opt_.value()); }
+    constexpr const T&& value() const&& { return std::move(opt_.value()); }
+
+    template <typename U = T>
+    constexpr T value_or(U&& default_value) const {
+        return opt_.value_or(std::forward<U>(default_value));
+    }
+
+    constexpr T* operator->() { return &*opt_; }
+    constexpr const T* operator->() const { return &*opt_; }
+    constexpr T& operator*() { return *opt_; }
+    constexpr const T& operator*() const { return *opt_; }
+
+    constexpr bool has_value() const { return opt_.has_value(); }
+    explicit constexpr operator bool() const { return has_value(); }
+
+    nullable& operator=(const nullable& other) = default;
+    nullable& operator=(nullable&& other) = default;
+
+    nullable& operator=(decltype(nullptr)) {
+        reset();
+        return *this;
+    }
+
+    nullable& operator=(T value) {
+        opt_ = std::move(value);
+        return *this;
+    }
+
+    void reset() { opt_.reset(); }
+
+    void swap(nullable& other) { opt_.swap(other.opt_); }
+
+private:
+    optional<T> opt_;
+};
+
+template <typename T>
+class nullable<T, true> final {
+public:
+    using value_type = T;
+
+    constexpr nullable()
+        : value_(nullptr) {}
+    explicit constexpr nullable(decltype(nullptr))
+        : value_(nullptr) {}
+    explicit constexpr nullable(T value)
+        : value_(std::move(value)) {}
+    nullable(const nullable& other) = default;
+    nullable(nullable&& other)
+        : value_(std::move(other.value_)) {
+        other.value_ = nullptr;
+    }
+    ~nullable() = default;
+
+    constexpr T& value() & {
+        assert(has_value());
+        return value_;
+    }
+    constexpr const T& value() const& {
+        assert(has_value());
+        return value_;
+    }
+    constexpr T&& value() && {
+        assert(has_value());
+        return std::move(value_);
+    }
+    constexpr const T&& value() const&& {
+        assert(has_value());
+        return std::move(value_);
+    }
+
+    template <typename U = T>
+    constexpr T value_or(U&& default_value) const {
+        return has_value() ? value_ : static_cast<T>(std::forward<U>(default_value));
+    }
+
+    constexpr T* operator->() { return &value_; }
+    constexpr const T* operator->() const { return &value_; }
+    constexpr T& operator*() { return value_; }
+    constexpr const T& operator*() const { return value_; }
+
+    constexpr bool has_value() const { return !(value_ == nullptr); }
+    explicit constexpr operator bool() const { return has_value(); }
+
+    nullable& operator=(const nullable& other) = default;
+    nullable& operator=(nullable&& other) {
+        if (&other == this)
+            return *this;
+        value_ = std::move(other.value_);
+        other.value_ = nullptr;
+        return *this;
+    }
+
+    nullable& operator=(decltype(nullptr)) {
+        reset();
+        return *this;
+    }
+
+    nullable& operator=(T value) {
+        value_ = std::move(value);
+        return *this;
+    }
+
+    void reset() { value_ = nullptr; }
+
+    void swap(nullable& other) {
+        using std::swap;
+        swap(value_, other.value_);
+    }
+
+private:
+    T value_;
+};
+
+template <typename T>
+void swap(nullable<T>& a, nullable<T>& b) {
+    a.swap(b);
+}
+
+template <typename T>
+constexpr bool operator==(const nullable<T>& lhs, decltype(nullptr)) {
+    return !lhs.has_value();
+}
+template <typename T>
+constexpr bool operator!=(const nullable<T>& lhs, decltype(nullptr)) {
+    return lhs.has_value();
+}
+
+template <typename T>
+constexpr bool operator==(decltype(nullptr), const nullable<T>& rhs) {
+    return !rhs.has_value();
+}
+template <typename T>
+constexpr bool operator!=(decltype(nullptr), const nullable<T>& rhs) {
+    return rhs.has_value();
+}
+
+template <typename T, typename U>
+constexpr bool operator==(const nullable<T>& lhs, const nullable<U>& rhs) {
+    return (lhs.has_value() == rhs.has_value()) && (!lhs.has_value() || *lhs == *rhs);
+}
+template <typename T, typename U>
+constexpr bool operator!=(const nullable<T>& lhs, const nullable<U>& rhs) {
+    return (lhs.has_value() != rhs.has_value()) || (lhs.has_value() && *lhs != *rhs);
+}
+
+template <typename T, typename U>
+constexpr bool operator==(const nullable<T>& lhs, const U& rhs) {
+    return (lhs.has_value() != is_null(rhs)) && (!lhs.has_value() || *lhs == rhs);
+}
+template <typename T, typename U>
+constexpr bool operator!=(const nullable<T>& lhs, const U& rhs) {
+    return (lhs.has_value() == is_null(rhs)) || (lhs.has_value() && *lhs != rhs);
+}
+
+template <typename T, typename U>
+constexpr bool operator==(const T& lhs, const nullable<U>& rhs) {
+    return (is_null(lhs) != rhs.has_value()) && (!rhs.has_value() || lhs == *rhs);
+}
+template <typename T, typename U>
+constexpr bool operator!=(const T& lhs, const nullable<U>& rhs) {
+    return (is_null(lhs) == rhs.has_value()) || (rhs.has_value() && lhs != *rhs);
+}
+
+} // namespace fit
+
+#endif // LIB_FIT_NULLABLE_H_
diff --git a/pkg/fit/include/lib/fit/optional.h b/pkg/fit/include/lib/fit/optional.h
new file mode 100644
index 0000000..929f05b
--- /dev/null
+++ b/pkg/fit/include/lib/fit/optional.h
@@ -0,0 +1,298 @@
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef LIB_FIT_OPTIONAL_H_
+#define LIB_FIT_OPTIONAL_H_
+
+#include <assert.h>
+
+#include <new>
+#include <type_traits>
+#include <utility>
+
+namespace fit {
+namespace internal {
+
+template <typename T, bool = std::is_assignable<T&, const T&>::value>
+struct copy_assign_or_reconstruct final {
+    static void assign(T* dest, const T& source) {
+        dest->~T();
+        new (dest) T(source);
+    }
+};
+
+template <typename T>
+struct copy_assign_or_reconstruct<T, true> final {
+    static void assign(T* dest, const T& source) {
+        *dest = source;
+    }
+};
+
+template <typename T, bool = std::is_assignable<T&, T&&>::value>
+struct move_assign_or_reconstruct final {
+    static void assign(T* dest, T&& source) {
+        dest->~T();
+        new (dest) T(std::move(source));
+    }
+
+    static void swap(T& a, T& b) {
+        T temp(std::move(a));
+        a.~T();
+        new (&a) T(std::move(b));
+        b.~T();
+        new (&b) T(std::move(temp));
+    }
+};
+
+template <typename T>
+struct move_assign_or_reconstruct<T, true> final {
+    static void assign(T* dest, T&& source) {
+        *dest = std::move(source);
+    }
+
+    static void swap(T& a, T& b) {
+        using std::swap;
+        swap(a, b);
+    }
+};
+
+} // namespace internal
+
+// A sentinel value for |fit::optional<T>| indicating that it contains
+// no value.
+struct nullopt_t {
+    explicit constexpr nullopt_t(int) {}
+};
+static constexpr nullopt_t nullopt(0);
+
+// A minimal implementation of an |std::optional<T>| work-alike for C++ 14.
+//
+// See also |fit::nullable<T>| which may be more efficient in certain
+// circumstances if T can be initialized, assigned, and compared with
+// nullptr.
+//
+// TODO(US-90): The initial implementation only covers a minimal subset of the
+// std::optional API.  Flesh this out more fully then define fit::optional
+// to be an alias for std::optional when compiling with C++ 17.
+template <typename T>
+class optional final {
+public:
+    using value_type = T;
+
+    constexpr optional()
+        : has_value_(false) {}
+    constexpr optional(nullopt_t)
+        : has_value_(false) {}
+
+    explicit constexpr optional(T value)
+        : has_value_(true), value_(std::move(value)) {}
+
+    optional(const optional& other)
+        : has_value_(other.has_value_) {
+        if (has_value_) {
+            new (&value_) T(other.value_);
+        }
+    }
+
+    optional(optional&& other)
+        : has_value_(other.has_value_) {
+        if (has_value_) {
+            new (&value_) T(std::move(other.value_));
+            other.value_.~T();
+            other.has_value_ = false;
+        }
+    }
+
+    // TODO(US-90): Presence of this destructor makes the type non-literal.
+    // We should specialize this type to handle the case where T is literal
+    // explicitly so that expressions these types can be constexpr.
+    ~optional() {
+        if (has_value_) {
+            value_.~T();
+        }
+    }
+
+    constexpr T& value() & {
+        assert(has_value_);
+        return value_;
+    }
+
+    constexpr const T& value() const& {
+        assert(has_value_);
+        return value_;
+    }
+
+    constexpr T&& value() && {
+        assert(has_value_);
+        return std::move(value_);
+    }
+
+    constexpr const T&& value() const&& {
+        assert(has_value_);
+        return std::move(value_);
+    }
+
+    template <typename U = T>
+    constexpr T value_or(U&& default_value) const {
+        return has_value_ ? value_ : static_cast<T>(std::forward<U>(default_value));
+    }
+
+    constexpr T* operator->() { return &value_; }
+    constexpr const T* operator->() const { return &value_; }
+    constexpr T& operator*() { return value_; }
+    constexpr const T& operator*() const { return value_; }
+
+    bool has_value() const { return has_value_; }
+    explicit operator bool() const { return has_value(); }
+
+    optional& operator=(const optional& other) {
+        if (&other == this)
+            return *this;
+        if (has_value_) {
+            if (other.has_value_) {
+                ::fit::internal::copy_assign_or_reconstruct<T>::assign(
+                    &value_, other.value_);
+            } else {
+                reset();
+            }
+        } else if (other.has_value_) {
+            new (&value_) T(other.value_);
+            has_value_ = true;
+        }
+        return *this;
+    }
+
+    optional& operator=(optional&& other) {
+        if (&other == this)
+            return *this;
+        if (has_value_) {
+            if (other.has_value_) {
+                ::fit::internal::move_assign_or_reconstruct<T>::assign(
+                    &value_, std::move(other.value_));
+                other.value_.~T();
+                other.has_value_ = false;
+            } else {
+                reset();
+            }
+        } else if (other.has_value_) {
+            new (&value_) T(std::move(other.value_));
+            has_value_ = true;
+            other.value_.~T();
+            other.has_value_ = false;
+        }
+        return *this;
+    }
+
+    optional& operator=(nullopt_t) {
+        reset();
+        return *this;
+    }
+
+    optional& operator=(T value) {
+        if (has_value_) {
+            ::fit::internal::move_assign_or_reconstruct<T>::assign(
+                &value_, std::move(value));
+        } else {
+            new (&value_) T(std::move(value));
+            has_value_ = true;
+        }
+        return *this;
+    }
+
+    void reset() {
+        if (has_value_) {
+            value_.~T();
+            has_value_ = false;
+        }
+    }
+
+    void swap(optional& other) {
+        if (&other == this)
+            return;
+        if (has_value_) {
+            if (other.has_value_) {
+                ::fit::internal::move_assign_or_reconstruct<T>::swap(
+                    value_, other.value_);
+            } else {
+                new (&other.value_) T(std::move(value_));
+                other.has_value_ = true;
+                value_.~T();
+                has_value_ = false;
+            }
+        } else if (other.has_value_) {
+            new (&value_) T(std::move(other.value_));
+            has_value_ = true;
+            other.value_.~T();
+            other.has_value_ = false;
+        }
+    }
+
+    template <typename... Args>
+    T& emplace(Args&&... args) {
+        reset();
+        new (&value_) T(std::forward<Args...>(args)...);
+        has_value_ = true;
+        return value_;
+    }
+
+private:
+    bool has_value_;
+    union {
+        T value_;
+    };
+};
+
+template <typename T>
+void swap(optional<T>& a, optional<T>& b) {
+    a.swap(b);
+}
+
+template <typename T>
+constexpr bool operator==(const optional<T>& lhs, nullopt_t) {
+    return !lhs.has_value();
+}
+template <typename T>
+constexpr bool operator!=(const optional<T>& lhs, nullopt_t) {
+    return lhs.has_value();
+}
+
+template <typename T>
+constexpr bool operator==(nullopt_t, const optional<T>& rhs) {
+    return !rhs.has_value();
+}
+template <typename T>
+constexpr bool operator!=(nullopt_t, const optional<T>& rhs) {
+    return rhs.has_value();
+}
+
+template <typename T, typename U>
+constexpr bool operator==(const optional<T>& lhs, const optional<U>& rhs) {
+    return (lhs.has_value() == rhs.has_value()) && (!lhs.has_value() || *lhs == *rhs);
+}
+template <typename T, typename U>
+constexpr bool operator!=(const optional<T>& lhs, const optional<U>& rhs) {
+    return (lhs.has_value() != rhs.has_value()) || (lhs.has_value() && *lhs != *rhs);
+}
+
+template <typename T, typename U>
+constexpr bool operator==(const optional<T>& lhs, const U& rhs) {
+    return lhs.has_value() && *lhs == rhs;
+}
+template <typename T, typename U>
+constexpr bool operator!=(const optional<T>& lhs, const U& rhs) {
+    return !lhs.has_value() || *lhs != rhs;
+}
+
+template <typename T, typename U>
+constexpr bool operator==(const T& lhs, const optional<U>& rhs) {
+    return rhs.has_value() && lhs == *rhs;
+}
+template <typename T, typename U>
+constexpr bool operator!=(const T& lhs, const optional<U>& rhs) {
+    return !rhs.has_value() || lhs != *rhs;
+}
+
+} // namespace fit
+
+#endif // LIB_FIT_OPTIONAL_H_
diff --git a/pkg/fit/include/lib/fit/promise.h b/pkg/fit/include/lib/fit/promise.h
new file mode 100644
index 0000000..ece9e75
--- /dev/null
+++ b/pkg/fit/include/lib/fit/promise.h
@@ -0,0 +1,1520 @@
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef LIB_FIT_PROMISE_H_
+#define LIB_FIT_PROMISE_H_
+
+#include <assert.h>
+
+#include <tuple>
+#include <type_traits>
+#include <utility>
+
+#include "function.h"
+#include "promise_internal.h"
+#include "result.h"
+#include "variant.h"
+
+namespace fit {
+
+// A |fit::promise| is a building block for asynchronous control flow that
+// wraps an asynchronous task in the form of a "continuation" that is
+// repeatedly invoked by an executor until it produces a result.
+//
+// Additional asynchronous tasks can be chained onto the promise using
+// a variety of combinators such as |then()|.
+//
+// Use |fit::make_promise()| to create a promise.
+// Use |fit::future| to more conveniently hold a promise or its result.
+// Use |fit::pending_task| to wrap a promise as a pending task for execution.
+// Use |fit::executor| to execute a pending task.
+// See examples below.
+//
+// Always look to the future; never look back.
+//
+// SYNOPSIS
+//
+// |V| is the type of value produced when the completes successfully.
+// Defaults to |void|.
+//
+// |E| is the type of error produced when the completes with an error.
+// Defaults to |void|.
+//
+// Class members are documented in |fit::promise_impl|.
+//
+// CHAINING PROMISES USING COMBINATORS
+//
+// Promises can be chained together using combinators such as |then()|
+// which consume the original promise(s) and return a new combined promise.
+//
+// For example, the |then()| combinator returns a promise that has the effect
+// of asynchronously awaiting completion of the prior promise (the instance
+// upon which |then()| was called) then delivering its result to a handler
+// function.
+//
+// Available combinators defined in this library:
+//
+//    |then()|: run a handler when prior promise completes
+//    |and_then()|: run a handler when prior promise completes successfully
+//    |or_else()|: run a handler when prior promise completes with an error
+//    |inspect()|: examine result of prior promise
+//    |discard_result()|: discard result and unconditionally return
+//                        fit::result<> when prior promise completes
+//    |wrap_with()|: applies a wrapper to the promise
+//    |box()|: wraps the promise's continuation into a |fit::function|
+//    |fit::join_promises()|: await multiple promises, once they all complete
+//                            return a tuple of their results
+//
+// You can also create your own custom combinators by crafting new
+// types of continuations.
+//
+// CONTINUATIONS AND HANDLERS
+//
+// Internally, |fit::promise| wraps a continuation (a kind of callable
+// object) that holds the state of the asynchronous task and provides a
+// means for making progress through repeated invocation.
+//
+// A promise's continuation is generated through the use of factories
+// such as |make_promise()| and combinators such as |then()|.  Most of
+// these functions accept a client-supplied "handler" (another kind
+// of callable object, often a lambda expression) which performs the actual
+// computations.
+//
+// Continuations have a very regular interface: they always accept a
+// |fit::context&| argument and return a |fit::result|.  Conversely, handlers
+// have a very flexible interface: clients can provide them in many forms
+// all of which are documented by the individual functions which consume them.
+// It's pretty easy to use: the library takes care of wrapping client-supplied
+// handlers of all supported forms into the continuations it uses internally.
+//
+// THEORY OF OPERATION
+//
+// On its own, a promise is "inert"; it only makes progress in response to
+// actions taken by its owner.  The state of the promise never changes
+// spontaneously or concurrently.
+//
+// Typically, a promise is executed by wrapping it into a |fit::pending_task|
+// and scheduling it for execution using |fit::executor::schedule_task()|.
+// A promise's |operator(fit::context&)| can also be invoked directly by its owner
+// from within the scope of another task (this is used to implement combinators
+// and futures) though the principle is the same.
+//
+// |fit::executor| is an abstract class that encapsulates a strategy for
+// executing tasks.  The executor is responsible for invoking each tasks's
+// continuation until the task returns a non-pending result, indicating that
+// the task has been completed.
+//
+// The method of execution and scheduling of each continuation call is left
+// to the discretion of each executor implementation.  Typical executor
+// implementations may dispatch tasks on an event-driven message loop or on
+// a thread pool.  Developers are responsible for selecting appropriate
+// executor implementations for their programs.
+//
+// During each invocation, the executor passes the continuation an execution
+// context object represented by a subclass of |fit::context|.  The continuation
+// attempts to make progress then returns a value of type |fit::result| to
+// indicate whether it completed successfully (signaled by |fit::ok()|),
+// failed with an error (signaled by |fit::error()|, or was unable to complete
+// the task during that invocation (signaled by |fit::pending()|).
+// For example, a continuation may be unable to complete the task if it must
+// asynchronously await completion of an I/O or IPC operation before it
+// can proceed any further.
+//
+// If the continuation was unable to complete the task during its invocation,
+// it may to call |fit::context::suspend_task()| to acquire a
+// |fit::suspended_task| object.  The continuation then arranges for the
+// task to be resumed asynchronously (with |fit::suspended_task::resume_task()|)
+// once it becomes possible for the promise to make forward progress again.
+// Finally, the continuation returns returns |fit::pending()| to indicate to
+// the executor that it was unable to complete the task during that invocation.
+//
+// When the executor receives a pending result from a task's continuation,
+// it moves the task into a table of suspended tasks.  A suspended task
+// is considered abandoned if has not been resume and all remaining
+// |fit::suspended_task| handles representing it have been dropped.
+// When a task is abandoned, the executor removes it from its table of
+// suspended tasks and destroys the task because it is not possible for the task
+// to be resumed or to make progress from that state.
+//
+// See also |fit::single_threaded_executor| for a simple executor implementation.
+//
+// BOXED AND UNBOXED PROMISES
+//
+// To make combination and execution as efficient as possible, the promises
+// returned by |fit::make_promise| and by combinators are parameterized by
+// complicated continuation types that are hard to describe, often consisting of
+// nested templates and lambdas.  These are referred to as "unboxed"
+// promises.  In contrast, "boxed" promises are parameterized by a
+// a |fit::function| that hides (or "erases") the type of the continuation
+// thereby yielding type that is easier to describe.
+//
+// You can recognize boxed and unboxed promises by their types.
+// Here are two examples:
+//
+// - A boxed promise type: `fit::promise<void, void>` which is an alias for
+//  `fit::promise_impl<void, void, std::function<fit::result<void, void>>`.
+// - An unboxed promise type: `fit::promise_impl<void, void,
+//   fit::internal::then_continuation<...something unintelligible...>>`
+//
+// Although boxed promises are easier to manipulate, they may cause the
+// continuation to be allocated on the heap.  Chaining boxed promises can
+// result in multiple allocations being produced.
+//
+// Conversely, unboxed promises have full type information.  Not only does
+// this defer heap allocation but it also makes it easier for the C++
+// compiler to fuse a chains of unboxed promises together into a single
+// object that is easier to optimize.
+//
+// Unboxed promises can be boxed by assigning them to a boxed promise
+// type (such as |fit::promise<>|) or using the |box()| combinator.
+//
+// As a rule of thumb, always defer boxing of promises until it is necessary
+// to transport them using a simpler type.
+//
+// Do this: (chaining as a single expression performs at most one heap allocation)
+//
+//     fit::promise<> f = fit::make_promise([] { ... });
+//         .then([](fit::result<> result) { ... });
+//         .and_then([] { ... });
+//
+// Or this: (still only performs at most one heap allocation)
+//
+//     auto f = fit::make_promise([] { ... });
+//     auto g = f.then([](fit::result<> result) { ... });
+//     auto h = g.and_then([] { ... });
+//     fit::promise<> boxed_h = h;
+//
+// But don't do this: (incurs up to three heap allocations due to eager boxing)
+//
+//     fit::promise<> f = fit::make_promise([] { ... });
+//     fit::promise<> g = f.then([](fit::result<> result) { ... });
+//     fit::promise<> h = g.and_then([] { ... });
+//
+// SINGLE OWNERSHIP MODEL
+//
+// Promises have single-ownership semantics.  This means that there
+// can only be at most one reference to the task represented by its
+// continuation along with any state held by that continuation.
+//
+// When a combinator is applied to a promise, ownership of its continuation
+// is transferred to the combined promise, leaving the original promise
+// in an "empty" state without a continuation.  Note that it is an error
+// to attempt to invoke an empty promise (will assert at runtime).
+//
+// This model greatly simplifies reasoning about object lifetime.
+// If a promise goes out of scope without completing its task, the task
+// is considered "abandoned", causing all associated state to be destroyed.
+//
+// Note that a promise may capture references to other objects whose lifetime
+// differs from that of the promise.  It is the responsibility of the promise
+// to ensure reachability of the objects whose reference it captures such
+// as by using reference counted pointers, weak pointers, or other appropriate
+// mechanisms to ensure memory safety.
+//
+// THREADING MODEL
+//
+// Promise objects are not thread-safe themselves.  You cannot call their
+// methods concurrently (or re-entrantly).  However, promises can safely
+// be moved to other threads and executed there (unless their continuation
+// requires thread affinity for some reason but that's beyond the scope
+// of this document).
+//
+// This property of being thread-independent, combined with the single
+// ownership model, greatly simplifies the implementation of thread pool
+// based executors.
+//
+// RESULT RETENTION AND FIT::FUTURES
+//
+// A promise's continuation can only be executed to completion once.
+// After it completes, it cannot be run again.
+//
+// This method of execution is very efficient; the promise's result is returned
+// directly to its invoker; it is not copied or retained within the promise
+// object itself.  It is entirely the caller's responsibility to decide how to
+// consume or retain the result if need be.
+//
+// For example, the caller can move the promise into a |fit::future| to
+// more conveniently hold either the promise or its result upon completion.
+//
+// CLARIFICATION OF NOMENCLATURE
+//
+// In this library, the words "promise" and "future" have the following
+// definitions:
+//
+// - A *promise* holds the function that performs an asynchronous task.
+//   It is the means to produce a value.
+// - A *future* holds the value produced by an asynchronous task or a
+//   promise to produce that value if the task has not yet completed.
+//   It is a proxy for a value that is to be computed.
+//
+// Be aware that other libraries may use these terms slightly differently.
+//
+// For more information about the theory of futures and promises, see
+// https://en.wikipedia.org/wiki/Futures_and_promises.
+//
+// COMPARISON WITH STD::FUTURE
+//
+// |std::future| provides a mechanism for running asynchronous tasks
+// and awaiting their results on other threads.  Waiting can be performed
+// either by blocking the waiting thread or by polling the future.
+// The manner in which tasks are scheduled and executed is entirely
+// controlled by the C++ standard library and offers limited control
+// to developers.
+//
+// |fit::promise| and |fit::future| provide a mechanism for running asynchronous
+// tasks, chaining additional tasks using combinators, and awaiting their
+// results.  An executor is responsible for suspending tasks awaiting
+// results of other tasks and is at liberty to run other tasks on the
+// same thread rather than blocking.  In addition, developers can create custom
+// executors to implement their own policies for running tasks.
+//
+// Decoupling awaiting from blocking makes |fit::promise| quite versatile.
+// |fit::promise| can also interoperate with other task dispatching mechanisms
+// (including |std::future|) using adapters such as |fit::bridge|.
+//
+// EXAMPLE
+//
+// - https://fuchsia.googlesource.com/zircon/+/master/system/utest/fit/examples/promise_example1.cpp
+// - https://fuchsia.googlesource.com/zircon/+/master/system/utest/fit/examples/promise_example2.cpp
+//
+template <typename V = void, typename E = void>
+using promise = promise_impl<function<result<V, E>(fit::context&)>>;
+
+// Promise implementation details.
+// See |fit::promise| documentation for more information.
+template <typename Continuation>
+class promise_impl final {
+    static_assert(
+        ::fit::internal::is_continuation<Continuation>::value,
+        "Continuation type is invalid.  A continuation is a callable object "
+        "with this signature: fit::result<V, E>(fit::context&).");
+
+    using state_type = nullable<Continuation>;
+
+public:
+    // The type of callable object held by the promise.
+    // Its signature is: result_type(fit::context&).
+    using continuation_type = Continuation;
+
+    // The promise's result type.
+    // Equivalent to fit::result<value_type, error_type>.
+    using result_type = typename ::fit::internal::continuation_traits<
+        Continuation>::result_type;
+
+    // The type of value produced when the promise completes successfully.
+    // May be void.
+    using value_type = typename result_type::value_type;
+
+    // The type of value produced when the promise completes with an error.
+    // May be void.
+    using error_type = typename result_type::error_type;
+
+    // Creates an empty promise without a continuation.
+    // A continuation must be assigned before the promise can be used.
+    promise_impl() = default;
+    explicit promise_impl(decltype(nullptr)) {}
+
+    // Creates a promise with a continuation.
+    // If |continuation| equals nullptr then the promise is empty.
+    explicit promise_impl(continuation_type continuation)
+        : state_(std::move(continuation)) {}
+
+    // Converts from a promise holding a continuation that is assignable to
+    // to this promise's continuation type.
+    //
+    // This is typically used to create a promise with a boxed continuation
+    // type (such as |fit::function|) from an unboxed promise produced by
+    // |fit::make_promise| or by combinators.
+    //
+    // EXAMPLE
+    //
+    //     // f is a promise_impl with a complicated unboxed type
+    //     auto f = fit::make_promise([] { ... });
+    //
+    //     // g wraps f's continuation
+    //     fit::promise<> g = std::move(f);
+    //
+    template <typename OtherContinuation,
+              typename = std::enable_if_t<
+                  std::is_constructible<continuation_type,
+                                        OtherContinuation&&>::value>>
+    promise_impl(promise_impl<OtherContinuation> other)
+        : state_(other.state_.has_value()
+                     ? state_type(continuation_type(std::move(*other.state_)))
+                     : state_type()) {}
+
+    // Creates a promise by taking the continuation from another promise,
+    // leaving the other promise empty.
+    promise_impl(promise_impl&& other) = default;
+
+    // Destroys the promise, releasing its continuation.
+    ~promise_impl() = default;
+
+    // Returns true if the promise is non-empty (has a valid continuation).
+    explicit operator bool() const { return state_.has_value(); }
+
+    // Invokes the promise's continuation.
+    //
+    // This method should be called by an executor to evaluate the promise.
+    // If the result's state is |result_state::pending| then the executor
+    // is responsible for arranging to invoke the promise's continuation
+    // again once it determines that it is possible to make progress
+    // towards completion of the promise encapsulated within the promise.
+    //
+    // Once the continuation returns a result with status |result_state::ok|
+    // or |result_state::error|, the promise is assigned an empty continuation.
+    //
+    // Asserts that the promise is non-empty.
+    result_type operator()(context& context) {
+        assert(state_.has_value());
+        result_type result = (*state_)(context);
+        if (!result.is_pending())
+            state_.reset();
+        return result;
+    }
+
+    // Takes the promise's continuation, leaving it in an empty state.
+    // Asserts that the promise is non-empty.
+    continuation_type take_continuation() {
+        assert(state_.has_value());
+        auto continuation = std::move(state_.value());
+        state_.reset();
+        return continuation;
+    }
+
+    // Assigns the promise by taking the continuation from another promise,
+    // leaving the other promise empty.
+    promise_impl& operator=(promise_impl&& other) = default;
+
+    // Discards the promise's continuation, leaving it empty.
+    promise_impl& operator=(decltype(nullptr)) {
+        state_.reset();
+        return *this;
+    }
+
+    // Assigns the promise's continuation.
+    promise_impl& operator=(continuation_type continuation) {
+        state_ = std::move(continuation);
+        return *this;
+    }
+
+    // Swaps the promises' continuations.
+    void swap(promise_impl& other) {
+        using std::swap;
+        swap(state_, other.state_);
+    }
+
+    // Returns an unboxed promise which invokes the specified handler
+    // function after this promise completes (successfully or unsuccessfully),
+    // passing its result.
+    //
+    // The received result's state is guaranteed to be either
+    // |fit::result_state::ok| or |fit::result_state::error|, never
+    // |fit::result_state::pending|.
+    //
+    // |handler| is a callable object (such as a lambda) which consumes the
+    // result of this promise and returns a new result with any value type
+    // and error type.  Must not be null.
+    //
+    // The handler must return one of the following types:
+    // - void
+    // - fit::result<new_value_type, new_error_type>
+    // - fit::ok<new_value_type>
+    // - fit::error<new_error_type>
+    // - fit::pending
+    // - fit::promise<new_value_type, new_error_type>
+    // - any callable or unboxed promise with the following signature:
+    //   fit::result<new_value_type, new_error_type>(fit::context&)
+    //
+    // The handler must accept one of the following argument lists:
+    // - (result_type)
+    // - (result_type&)
+    // - (const result_type&)
+    // - (fit::context&, result_type)
+    // - (fit::context&, result_type&)
+    // - (fit::context&, const result_type&)
+    //
+    // Asserts that the promise is non-empty.
+    // This method consumes the promise's continuation, leaving it empty.
+    //
+    // EXAMPLE
+    //
+    //     auto f = fit::make_promise(...)
+    //         .then([] (fit::result<int, std::string> result)
+    //                   -> fit::result<std::string, void> {
+    //             if (result.is_ok()) {
+    //                 printf("received value: %d\n", result.value());
+    //                 if (result.value() % 15 == 0)
+    //                     return ::fit::ok("fizzbuzz");
+    //                 if (result.value() % 3 == 0)
+    //                     return ::fit::ok("fizz");
+    //                 if (result.value() % 5 == 0)
+    //                     return ::fit::ok("buzz");
+    //                 return ::fit::ok(std::to_string(result.value()));
+    //             } else {
+    //                 printf("received error: %s\n", result.error().c_str());
+    //                 return ::fit::error();
+    //             }
+    //         })
+    //         .then(...);
+    //
+    template <typename ResultHandler>
+    promise_impl<::fit::internal::then_continuation<promise_impl, ResultHandler>>
+    then(ResultHandler handler) {
+        static_assert(is_callable<ResultHandler>::value,
+                      "ResultHandler must be a callable object.");
+
+        assert(!is_null(handler));
+        assert(state_.has_value());
+        return make_promise_with_continuation(
+            ::fit::internal::then_continuation<promise_impl, ResultHandler>(
+                std::move(*this), std::move(handler)));
+    }
+
+    // Returns an unboxed promise which invokes the specified handler
+    // function after this promise completes successfully, passing its
+    // resulting value.
+    //
+    // |handler| is a callable object (such as a lambda) which consumes the
+    // result of this promise and returns a new result with any value type
+    // but the same error type.  Must not be null.
+    //
+    // The handler must return one of the following types:
+    // - void
+    // - fit::result<new_value_type, error_type>
+    // - fit::ok<new_value_type>
+    // - fit::error<error_type>
+    // - fit::pending
+    // - fit::promise<new_value_type, error_type>
+    // - any callable or unboxed promise with the following signature:
+    //   fit::result<new_value_type, error_type>(fit::context&)
+    //
+    // The handler must accept one of the following argument lists:
+    // - (value_type)
+    // - (value_type&)
+    // - (const value_type&)
+    // - (fit::context&, value_type)
+    // - (fit::context&, value_type&)
+    // - (fit::context&, const value_type&)
+    //
+    // Asserts that the promise is non-empty.
+    // This method consumes the promise's continuation, leaving it empty.
+    //
+    // EXAMPLE
+    //
+    //     auto f = fit::make_promise(...)
+    //         .and_then([] (int value) {
+    //             printf("received value: %d\n", value);
+    //             if (value % 15 == 0)
+    //                 return ::fit::ok("fizzbuzz");
+    //             if (value % 3 == 0)
+    //                 return ::fit::ok("fizz");
+    //             if (value % 5 == 0)
+    //                 return ::fit::ok("buzz");
+    //             return ::fit::ok(std::to_string(value));
+    //         })
+    //         .then(...);
+    //
+    template <typename ValueHandler>
+    promise_impl<::fit::internal::and_then_continuation<promise_impl, ValueHandler>>
+    and_then(ValueHandler handler) {
+        static_assert(is_callable<ValueHandler>::value,
+                      "ValueHandler must be a callable object.");
+
+        assert(!is_null(handler));
+        assert(state_.has_value());
+        return make_promise_with_continuation(
+            ::fit::internal::and_then_continuation<promise_impl, ValueHandler>(
+                std::move(*this), std::move(handler)));
+    }
+
+    // Returns an unboxed promise which invokes the specified handler
+    // function after this promise completes with an error, passing its
+    // resulting error.
+    //
+    // |handler| is a callable object (such as a lambda) which consumes the
+    // result of this promise and returns a new result with any error type
+    // but the same value type.  Must not be null.
+    //
+    // The handler must return one of the following types:
+    // - void
+    // - fit::result<value_type, new_error_type>
+    // - fit::ok<value_type>
+    // - fit::error<new_error_type>
+    // - fit::pending
+    // - fit::promise<value_type, new_error_type>
+    // - any callable or unboxed promise with the following signature:
+    //   fit::result<value_type, new_error_type>(fit::context&)
+    //
+    // The handler must accept one of the following argument lists:
+    // - (error_type)
+    // - (error_type&)
+    // - (const error_type&)
+    // - (fit::context&, error_type)
+    // - (fit::context&, error_type&)
+    // - (fit::context&, const error_type&)
+    //
+    // Asserts that the promise is non-empty.
+    // This method consumes the promise's continuation, leaving it empty.
+    //
+    // EXAMPLE
+    //
+    //     auto f = fit::make_promise(...)
+    //         .or_else([] (std::string error) {
+    //             printf("received error: %s\n", error.c_str());
+    //             return ::fit::error();
+    //         })
+    //         .then(...);
+    //
+    template <typename ErrorHandler>
+    promise_impl<::fit::internal::or_else_continuation<promise_impl, ErrorHandler>>
+    or_else(ErrorHandler handler) {
+        static_assert(is_callable<ErrorHandler>::value,
+                      "ErrorHandler must be a callable object.");
+
+        assert(!is_null(handler));
+        assert(state_.has_value());
+        return make_promise_with_continuation(
+            ::fit::internal::or_else_continuation<promise_impl, ErrorHandler>(
+                std::move(*this), std::move(handler)));
+    }
+
+    // Returns an unboxed promise which invokes the specified handler
+    // function after this promise completes (successfully or unsuccessfully),
+    // passing it the promise's result then delivering the result onwards
+    // to the next promise once the handler returns.
+    //
+    // The handler receive a copy, const reference, or non-const reference
+    // depending on the signature of the handler's last argument.
+    //
+    // - Copies and const references are especially useful for inspecting a
+    //   result mid-stream without modification, such as printing it for
+    //   debugging.
+    // - Non-const references are especially useful for synchronously
+    //   modifying a result mid-stream, such as clamping its bounds or
+    //   injecting a default value.
+    //
+    // |handler| is a callable object (such as a lambda) which can examine
+    // or modify the incoming result.  Unlike |then()|, the handler does
+    // not need to propagate the result onwards.  Must not be null.
+    //
+    // The handler must return one of the following types:
+    // - void
+    //
+    // The handler must accept one of the following argument lists:
+    // - (result_type)
+    // - (result_type&)
+    // - (const result_type&)
+    // - (fit::context&, result_type)
+    // - (fit::context&, result_type&)
+    // - (fit::context&, const result_type&)
+    //
+    // Asserts that the promise is non-empty.
+    // This method consumes the promise's continuation, leaving it empty.
+    //
+    // EXAMPLE
+    //
+    //     auto f = fit::make_promise(...)
+    //         .inspect([] (const fit::result<int, std::string>& result) {
+    //             if (result.is_ok())
+    //                 printf("received value: %d\n", result.value());
+    //             else
+    //                 printf("received error: %s\n", result.error().c_str());
+    //         })
+    //         .then(...);
+    //
+    template <typename InspectHandler>
+    promise_impl<::fit::internal::inspect_continuation<promise_impl, InspectHandler>>
+    inspect(InspectHandler handler) {
+        static_assert(is_callable<InspectHandler>::value,
+                      "InspectHandler must be a callable object.");
+        static_assert(std::is_void<typename callable_traits<
+                          InspectHandler>::return_type>::value,
+                      "InspectHandler must return void.");
+
+        assert(!is_null(handler));
+        assert(state_.has_value());
+        return make_promise_with_continuation(
+            ::fit::internal::inspect_continuation<promise_impl, InspectHandler>(
+                std::move(*this), std::move(handler)));
+    }
+
+    // Returns an unboxed promise which discards the result of this promise
+    // once it completes, thereby always producing a successful result of
+    // type fit::result<void, void> regardless of whether this promise
+    // succeeded or failed.
+    //
+    // Asserts that the promise is non-empty.
+    // This method consumes the promise's continuation, leaving it empty.
+    //
+    // EXAMPLE
+    //
+    //     auto f = fit::make_promise(...)
+    //         .discard_result()
+    //         .then(...);
+    //
+    promise_impl<::fit::internal::discard_result_continuation<promise_impl>>
+    discard_result() {
+        assert(state_.has_value());
+        return make_promise_with_continuation(
+            ::fit::internal::discard_result_continuation<promise_impl>(
+                std::move(*this)));
+    }
+
+    // Applies a |wrapper| to the promise.  Invokes the wrapper's |wrap()|
+    // method, passes the promise to the wrapper by value followed by any
+    // additional |args| passed to |wrap_with()|, then returns the wrapper's
+    // result.
+    //
+    // |Wrapper| is a type that implements a method called |wrap()| which
+    // accepts a promise as its argument and produces a wrapped result of
+    // any type, such as another promise.
+    //
+    // Asserts that the promise is non-empty.
+    // This method consumes the promise's continuation, leaving it empty.
+    //
+    // EXAMPLE
+    //
+    // In this example, |fit::sequencer| is a wrapper type that imposes
+    // FIFO execution order onto a sequence of wrapped promises.
+    //
+    //     // This wrapper type is intended to be applied to
+    //     // a sequence of promises so we store it in a variable.
+    //     fit::sequencer seq;
+    //
+    //     // This task consists of some amount of work that must be
+    //     // completed sequentially followed by other work that can
+    //     // happen in any order.  We use |wrap_with()| to wrap the
+    //     // sequential work with the sequencer.
+    //     fit::promise<> perform_complex_task() {
+    //         return fit::make_promise([] { /* do sequential work */ })
+    //             .then([] (fit::result<> result) { /* this will also be wrapped */ })
+    //             .wrap_with(seq)
+    //             .then([] (fit::result<> result) { /* do more work */ });
+    //     }
+    //
+    // This example can also be written without using |wrap_with()|.
+    // The behavior is equivalent but the syntax may seem more awkward.
+    //
+    //     fit::sequencer seq;
+    //
+    //     promise<> perform_complex_task() {
+    //         return seq.wrap(
+    //                 fit::make_promise([] { /* sequential work */ })
+    //             ).then([] (fit::result<> result) { /* more work */ });
+    //     }
+    //
+    template <typename Wrapper, typename... Args>
+    decltype(auto) wrap_with(Wrapper& wrapper, Args... args) {
+        assert(state_.has_value());
+        return wrapper.wrap(std::move(*this),
+                            std::forward<Args>(args)...);
+    }
+
+    // Wraps the promise's continuation into a |fit::function|.
+    //
+    // A boxed promise is easier to store and pass around than the unboxed
+    // promises produced by |fit::make_promise()| and combinators, though boxing
+    // may incur a heap allocation.
+    //
+    // It is a good idea to defer boxing the promise until after all
+    // desired combinators have been applied to prevent unnecessary heap
+    // allocation during intermediate states of the promise's construction.
+    //
+    // Returns an empty promise if this promise is empty.
+    // This method consumes the promise's continuation, leaving it empty.
+    //
+    // EXAMPLE
+    //
+    //     // f's is a fit::promise_impl<> whose continuation contains an
+    //     // anonymous type (the lambda)
+    //     auto f = fit::make_promise([] {});
+    //
+    //     // g's type will be fit::promise<> due to boxing
+    //     auto boxed_f = f.box();
+    //
+    //     // alternately, we can get exactly the same effect by assigning
+    //     // the unboxed promise to a variable of a named type instead of
+    //     // calling box()
+    //     fit::promise<> boxed_f = std::move(f);
+    //
+    promise_impl<function<result_type(context&)>> box() {
+        return std::move(*this);
+    }
+
+    promise_impl(const promise_impl&) = delete;
+    promise_impl& operator=(const promise_impl&) = delete;
+
+private:
+    template <typename>
+    friend class promise_impl;
+
+    state_type state_;
+};
+
+template <typename Continuation>
+void swap(promise_impl<Continuation>& a,
+          promise_impl<Continuation>& b) {
+    a.swap(b);
+}
+
+template <typename Continuation>
+bool operator==(const promise_impl<Continuation>& f,
+                decltype(nullptr)) {
+    return !f;
+}
+template <typename Continuation>
+bool operator==(decltype(nullptr),
+                const promise_impl<Continuation>& f) {
+    return !f;
+}
+template <typename Continuation>
+bool operator!=(const promise_impl<Continuation>& f,
+                decltype(nullptr)) {
+    return !!f;
+}
+template <typename Continuation>
+bool operator!=(decltype(nullptr),
+                const promise_impl<Continuation>& f) {
+    return !!f;
+}
+
+// Makes a promise containing the specified continuation.
+//
+// This function is used for making a promises given a callable object
+// that represents a valid continuation type.  In contrast,
+// |fit::make_promise()| supports a wider range of types and should be
+// preferred in most situations.
+//
+// |Continuation| is a callable object with the signature
+// fit::result<V, E>(fit::context&).
+template <typename Continuation>
+inline promise_impl<Continuation> make_promise_with_continuation(
+    Continuation continuation) {
+    return promise_impl<Continuation>(std::move(continuation));
+}
+
+// Returns an unboxed promise that wraps the specified handler.
+// The type of the promise's result is inferred from the handler's result.
+//
+// |handler| is a callable object (such as a lambda.  Must not be null.
+//
+// The handler must return one of the following types:
+// - void
+// - fit::result<value_type, error_type>
+// - fit::ok<value_type>
+// - fit::error<error_type>
+// - fit::pending
+// - fit::promise<value_type, error_type>
+// - any callable or unboxed promise with the following signature:
+//   fit::result<value_type, error_type>(fit::context&)
+//
+// The handler must accept one of the following argument lists:
+// - ()
+// - (fit::context&)
+//
+// See documentation of |fit::promise| for more information.
+//
+// SYNOPSIS
+//
+// |Handler| is the handler function type.  It is typically inferred by the
+// compiler from the |handler| argument.
+//
+// EXAMPLE
+//
+//     enum class weather_type { sunny, glorious, cloudy, eerie, ... };
+//
+//     weather_type look_outside() { ... }
+//     void wait_for_tomorrow(fit::suspended_task task) {
+//         ... arrange to call task.resume_task() tomorrow ...
+//     }
+//
+//     fit::promise<weather_type, std::string> wait_for_good_weather(int max_days) {
+//         return fit::make_promise([days_left = max_days] (fit::context context&) mutable
+//                             -> fit::result<int, std::string> {
+//             weather_type weather = look_outside();
+//             if (weather == weather_type::sunny || weather == weather_type::glorious)
+//                 return fit::ok(weather);
+//             if (days_left > 0) {
+//                 wait_for_tomorrow(context.suspend_task());
+//                 return fit::pending();
+//             }
+//             days_left--;
+//             return fit::error("nothing but grey skies");
+//         });
+//     }
+//
+//     auto f = wait_for_good_weather(7)
+//         .and_then([] (weather_type weather) { ... })
+//         .or_else([] (std::string error) { ... });
+//
+template <typename PromiseHandler>
+inline promise_impl<::fit::internal::context_handler_invoker<PromiseHandler>>
+make_promise(PromiseHandler handler) {
+    static_assert(is_callable<PromiseHandler>::value,
+                  "PromiseHandler must be a callable object.");
+
+    assert(!is_null(handler));
+    return make_promise_with_continuation(
+        ::fit::internal::promise_continuation<PromiseHandler>(
+            std::move(handler)));
+}
+
+// Jointly evaluates zero or more promises.
+// Returns a promise that produces a std::tuple<> containing the result
+// of each promise once they all complete.
+//
+// EXAMPLE
+//
+//     auto get_random_number() {
+//         return fit::make_promise([] { return rand() % 10 });
+//     }
+//
+//     auto get_random_product() {
+//         auto f = get_random_number();
+//         auto g = get_random_number();
+//         return fit::join_promises(std::move(f), std::move(g))
+//             .and_then([] (std::tuple<fit::result<int>, fit::result<int>> results) {
+//                 return fit::ok(results.get<0>.value() + results.get<1>.value());
+//             });
+//     }
+//
+template <typename... Promises>
+inline promise_impl<::fit::internal::join_continuation<Promises...>>
+join_promises(Promises... promises) {
+    return make_promise_with_continuation(
+        ::fit::internal::join_continuation<Promises...>(std::move(promises)...));
+}
+
+// Describes the status of a future.
+enum class future_state {
+    // The future neither holds a result nor a promise that could produce a result.
+    // An empty future cannot make progress until a promise or result is assigned to it.
+    empty,
+    // The future holds a promise that may eventually produce a result but
+    // it currently doesn't have a result.  The future's promise must be
+    // invoked in order to make progress from this state.
+    pending,
+    // The future holds a successful result.
+    ok,
+    // The future holds an error result.
+    error
+};
+
+// A |fit::future| holds onto a |fit::promise| until it has completed then
+// provides access to its |fit::result|.
+//
+// SYNOPSIS
+//
+// |V| is the type of value produced when the completes successfully.
+// Defaults to |void|.
+//
+// |E| is the type of error produced when the completes with an error.
+// Defaults to |void|.
+//
+// THEORY OF OPERATION
+//
+// A future has a single owner who is responsible for setting its promise
+// or result and driving its execution.  Unlike |fit::promise|, a future retains
+// the result produced by completion of its asynchronous task.  Result retention
+// eases the implementation of combined tasks that need to await the results
+// of other tasks before proceeding.
+//
+// See the example for details.
+//
+// A future can be in one of four states, depending on whether it holds...
+// - a successful result: |fit::future_state::ok|
+// - an error result: |fit::future_state::error|
+// - a promise that may eventually produce a result: |fit::future_state::pending|
+// - neither: |fit::future_state_empty|
+//
+// On its own, a future is "inert"; it only makes progress in response to
+// actions taken by its owner.  The state of the future never changes
+// spontaneously or concurrently.
+//
+// When the future's state is |fit::future_state::empty|, its owner is
+// responsible for setting the future's promise or result thereby moving the
+// future into the pending or ready state.
+//
+// When the future's state is |fit::future_state::pending|, its owner is
+// responsible for calling the future's |operator()| to invoke the promise.
+// If the promise completes and returns a result, the future will transition
+// to the ok or error state according to the result.  The promise itself will
+// then be destroyed since it has fulfilled its purpose.
+//
+// When the future's state is |fit::future_state::ok|, its owner is responsible
+// for consuming the stored value using |value()|, |take_value()|,
+// |result()|, |take_result()|, or |take_ok_result()|.
+//
+// When the future's state is |fit::future_state::error|, its owner is
+// responsible for consuming the stored error using |error()|, |take_error()|,
+// |result()|, |take_result()|, or |take_error_result()|.
+//
+// See also |fit::promise| for more information about promises and their
+// execution.
+//
+// EXAMPLE
+//
+// - https://fuchsia.googlesource.com/zircon/+/master/system/utest/fit/examples/promise_example2.cpp
+template <typename V = void, typename E = void>
+using future = future_impl<promise<V, E>>;
+
+// Future implementation details.
+// See |fit::future| documentation for more information.
+template <typename Promise>
+class future_impl final {
+public:
+    // The type of promise held by the future.
+    using promise_type = Promise;
+
+    // The promise's result type.
+    // Equivalent to fit::result<value_type, error_type>.
+    using result_type = typename Promise::result_type;
+
+    // The type of value produced when the promise completes successfully.
+    // May be void.
+    using value_type = typename Promise::value_type;
+
+    // The type of value produced when the promise completes with an error.
+    // May be void.
+    using error_type = typename Promise::error_type;
+
+    // Creates a future in the empty state.
+    future_impl() = default;
+    future_impl(decltype(nullptr)) {}
+
+    // Creates a future and assigns a promise to compute its result.
+    // If the promise is empty, the future enters the empty state.
+    // Otherwise the future enters the pending state.
+    explicit future_impl(promise_type promise) {
+        if (promise) {
+            state_.template emplace<1>(std::move(promise));
+        }
+    }
+
+    // Creates a future and assigns its result.
+    // If the result is pending, the future enters the empty state.
+    // Otherwise the future enters the ok or error state.
+    explicit future_impl(result_type result) {
+        if (result) {
+            state_.template emplace<2>(std::move(result));
+        }
+    }
+
+    // Moves from another future, leaving the other one in an empty state.
+    future_impl(future_impl&& other)
+        : state_(std::move(other.state_)) {
+        other.state_.template emplace<0>();
+    }
+
+    // Destroys the promise, releasing its promise and result (if any).
+    ~future_impl() = default;
+
+    // Returns the state of the future: empty, pending, ok, or error.
+    future_state state() const {
+        switch (state_.index()) {
+        case 0:
+            return future_state::empty;
+        case 1:
+            return future_state::pending;
+        case 2:
+            return state_.template get<2>().is_ok()
+                       ? future_state::ok
+                       : future_state::error;
+        }
+        __builtin_unreachable();
+    }
+
+    // Returns true if the future's state is not |fit::future_state::empty|:
+    // it either holds a result or holds a promise that can be invoked to make
+    // progress towards obtaining a result.
+    explicit operator bool() const { return !is_empty(); }
+
+    // Returns true if the future's state is |fit::future_state::empty|:
+    // it does not hold a result or a promise so it cannot make progress.
+    bool is_empty() const { return state() == fit::future_state::empty; }
+
+    // Returns true if the future's state is |fit::future_state::pending|:
+    // it does not hold a result yet but it does hold a promise that can be invoked
+    // to make progress towards obtaining a result.
+    bool is_pending() const { return state() == fit::future_state::pending; }
+
+    // Returns true if the future's state is |fit::future_state::ok|:
+    // it holds a value that can be retrieved using |value()|, |take_value()|,
+    // |result()|, |take_result()|, or |take_ok_result()|.
+    bool is_ok() const { return state() == fit::future_state::ok; }
+
+    // Returns true if the future's state is |fit::future_state::error|:
+    // it holds an error that can be retrieved using |error()|, |take_error()|,
+    // |result()|, |take_result()|, or |take_error_result()|.
+    bool is_error() const { return state() == fit::future_state::error; }
+
+    // Returns true if the future's state is either |fit::future_state::ok| or
+    // |fit::future_state::error|.
+    bool is_ready() const { return state_.index() == 2; }
+
+    // Evaluates the future and returns true if its result is ready.
+    // Asserts that the future is not empty.
+    //
+    // If the promise completes and returns a result, the future will transition
+    // to the ok or error state according to the result.  The promise itself will
+    // then be destroyed since it has fulfilled its purpose.
+    bool operator()(fit::context& context) {
+        switch (state_.index()) {
+        case 0:
+            return false;
+        case 1: {
+            result_type result = state_.template get<1>()(context);
+            if (!result)
+                return false;
+            state_.template emplace<2>(std::move(result));
+            return true;
+        }
+        case 2:
+            return true;
+        }
+        __builtin_unreachable();
+    }
+
+    // Gets a reference to the future's promise.
+    // Asserts that the future's state is |fit::future_state::pending|.
+    const promise_type& promise() const {
+        assert(is_pending());
+        return state_.template get<1>();
+    }
+
+    // Takes the future's promise, leaving it in an empty state.
+    // Asserts that the future's state is |fit::future_state::pending|.
+    promise_type take_promise() {
+        assert(is_pending());
+        auto promise = std::move(state_.template get<1>());
+        state_.template emplace<0>();
+        return promise;
+    }
+
+    // Gets a reference to the future's result.
+    // Asserts that the future's state is |fit::future_state::ok| or
+    // |fit::future_state::error|.
+    result_type& result() {
+        assert(is_ready());
+        return state_.template get<2>();
+    }
+    const result_type& result() const {
+        assert(is_ready());
+        return state_.template get<2>();
+    }
+
+    // Takes the future's result, leaving it in an empty state.
+    // Asserts that the future's state is |fit::future_state::ok| or
+    // |fit::future_state::error|.
+    result_type take_result() {
+        assert(is_ready());
+        auto result = std::move(state_.template get<2>());
+        state_.template emplace<0>();
+        return result;
+    }
+
+    // Gets a reference to the future's value.
+    // Asserts that the future's state is |fit::future_state::ok|.
+    template <typename R = value_type,
+              typename = std::enable_if_t<!std::is_void<R>::value>>
+    R& value() {
+        assert(is_ok());
+        return state_.template get<2>().value();
+    }
+    template <typename R = value_type,
+              typename = std::enable_if_t<!std::is_void<R>::value>>
+    const R& value() const {
+        assert(is_ok());
+        return state_.template get<2>().value();
+    }
+
+    // Takes the future's value, leaving it in an empty state.
+    // Asserts that the future's state is |fit::future_state::ok|.
+    template <typename R = value_type,
+              typename = std::enable_if_t<!std::is_void<R>::value>>
+    R take_value() {
+        assert(is_ok());
+        auto value = state_.template get<2>().take_value();
+        state_.template emplace<0>();
+        return value;
+    }
+    ok_result<value_type> take_ok_result() {
+        assert(is_ok());
+        auto result = state_.template get<2>().take_ok_result();
+        state_.template emplace<0>();
+        return result;
+    }
+
+    // Gets a reference to the future's error.
+    // Asserts that the future's state is |fit::future_state::error|.
+    template <typename R = error_type,
+              typename = std::enable_if_t<!std::is_void<R>::value>>
+    R& error() {
+        assert(is_error());
+        return state_.template get<2>().error();
+    }
+    template <typename R = error_type,
+              typename = std::enable_if_t<!std::is_void<R>::value>>
+    const R& error() const {
+        assert(is_error());
+        return state_.template get<2>().error();
+    }
+
+    // Takes the future's error, leaving it in an empty state.
+    // Asserts that the future's state is |fit::future_state::error|.
+    template <typename R = error_type,
+              typename = std::enable_if_t<!std::is_void<R>::value>>
+    R take_error() {
+        assert(is_error());
+        auto error = state_.template get<2>().take_error();
+        state_.template emplace<0>();
+        return error;
+    }
+    error_result<error_type> take_error_result() {
+        assert(is_error());
+        auto result = state_.template get<2>().take_error_result();
+        state_.template emplace<0>();
+        return result;
+    }
+
+    // Move assigns from another future, leaving the other one in an empty state.
+    future_impl& operator=(future_impl&& other) = default;
+
+    // Discards the future's promise and result, leaving it empty.
+    future_impl& operator=(decltype(nullptr)) {
+        state_.template emplace<0>();
+        return *this;
+    }
+
+    // Assigns a promise to compute the future's result.
+    // If the promise is empty, the future enters the empty state.
+    // Otherwise the future enters the pending state.
+    future_impl& operator=(promise_type promise) {
+        if (promise) {
+            state_.template emplace<1>(std::move(promise));
+        } else {
+            state_.template emplace<0>();
+        }
+        return *this;
+    }
+
+    // Assigns the future's result.
+    // If the result is pending, the future enters the empty state.
+    // Otherwise the future enters the ok or error state.
+    future_impl& operator=(result_type result) {
+        if (result) {
+            state_.template emplace<2>(std::move(result));
+        } else {
+            state_.template emplace<0>();
+        }
+        return *this;
+    }
+
+    // Swaps the futures' contents.
+    void swap(future_impl& other) {
+        using std::swap;
+        swap(state_, other.state_);
+    }
+
+    future_impl(const future_impl&) = delete;
+    future_impl& operator=(const future_impl&) = delete;
+
+private:
+    ::fit::internal::variant<::fit::internal::monostate,
+                             promise_type, result_type>
+        state_;
+};
+
+template <typename Promise>
+void swap(future_impl<Promise>& a, future_impl<Promise>& b) {
+    a.swap(b);
+}
+
+template <typename Promise>
+bool operator==(const future_impl<Promise>& f, decltype(nullptr)) {
+    return !f;
+}
+template <typename Promise>
+bool operator==(decltype(nullptr), const future_impl<Promise>& f) {
+    return !f;
+}
+template <typename Promise>
+bool operator!=(const future_impl<Promise>& f, decltype(nullptr)) {
+    return !!f;
+}
+template <typename Promise>
+bool operator!=(decltype(nullptr), const future_impl<Promise>& f) {
+    return !!f;
+}
+
+// Makes a future containing the specified promise.
+template <typename Promise>
+future_impl<Promise> make_future(Promise promise) {
+    return future_impl<Promise>(std::move(promise));
+}
+
+// A pending task holds a |fit::promise| that can be scheduled to run on
+// a |fit::executor| using |fit::executor::schedule_task()|.
+//
+// An executor repeatedly invokes a pending task until it returns true,
+// indicating completion.  Note that the promise's resulting value or error
+// is discarded since it is not meaningful to the executor.  If you need
+// to consume the result, use a combinator such as |fit::pending::then()|
+// to capture it prior to wrapping the promise into a pending task.
+//
+// See documentation of |fit::promise| for more information.
+class pending_task final {
+public:
+    // The type of promise held by this task.
+    using promise_type = promise<void, void>;
+
+    // Creates an empty pending task without a promise.
+    pending_task() = default;
+
+    // Creates a pending task that wraps an already boxed promise that returns
+    // |fit::result<void, void>|.
+    pending_task(promise_type promise)
+        : promise_(std::move(promise)) {}
+
+    // Creates a pending task that wraps any kind of promise, boxed or unboxed,
+    // regardless of its result type and with any context that is assignable
+    // from this task's context type.
+    template <typename Continuation>
+    pending_task(promise_impl<Continuation> promise)
+        : promise_(promise ? promise.discard_result().box() : promise_type()) {}
+
+    pending_task(pending_task&&) = default;
+    pending_task& operator=(pending_task&&) = default;
+
+    // Destroys the pending task, releasing its promise.
+    ~pending_task() = default;
+
+    // Returns true if the pending task is non-empty (has a valid promise).
+    explicit operator bool() const { return !!promise_; }
+
+    // Evaluates the pending task.
+    // If the task completes (returns a non-pending result), the task reverts
+    // to an empty state (because the promise it holds has reverted to an empty
+    // state) and returns true.
+    // It is an error to invoke this method if the pending task is empty.
+    bool operator()(fit::context& context) {
+        return !promise_(context).is_pending();
+    }
+
+    // Extracts the pending task's promise.
+    promise_type take_promise() {
+        return std::move(promise_);
+    }
+
+    pending_task(const pending_task&) = delete;
+    pending_task& operator=(const pending_task&) = delete;
+
+private:
+    promise_type promise_;
+};
+
+// Execution context for an asynchronous task, such as a |fit::promise|,
+// |fit::future|, or |fit::pending_task|.
+//
+// When a |fit::executor| executes a task, it provides the task with an
+// execution context which enables the task to communicate with the
+// executor and manage its own lifecycle.  Specialized executors may subclass
+// |fit::context| and offer additional methods beyond those which are
+// defined here, such as to provide access to platform-specific features
+// supported by the executor.
+//
+// The context provided to a task is only valid within the scope of a single
+// invocation; the task must not retain a reference to the context across
+// invocations.
+//
+// See documentation of |fit::promise| for more information.
+class context {
+public:
+    // Gets the executor that is running the task, never null.
+    virtual class executor* executor() const = 0;
+
+    // Obtains a handle that can be used to resume the task after it has been
+    // suspended.
+    //
+    // Clients should call this method before returning |fit::pending()| from
+    // the task.  See documentation on |fit::executor|.
+    virtual suspended_task suspend_task() = 0;
+
+    // Converts this context to a derived context type.
+    template <typename Context,
+              typename = std::enable_if_t<std::is_base_of<context, Context>::value>>
+    Context& as() & {
+        // TODO(CP-163): We should perform a run-time type check here rather
+        // than blindly casting.  That's why this method exists.
+        return static_cast<Context&>(*this);
+    }
+
+protected:
+    virtual ~context() = default;
+};
+
+// An abstract interface for executing asynchronous tasks, such as promises,
+// represented by |fit::pending_task|.
+//
+// EXECUTING TASKS
+//
+// An executor evaluates its tasks incrementally.  During each iteration
+// of the executor's main loop, it invokes the next task from its ready queue.
+//
+// If the task returns true, then the task is deemed to have completed.
+// The executor removes the tasks from its queue and destroys it since there
+// it nothing left to do.
+//
+// If the task returns false, then the task is deemed to have voluntarily
+// suspended itself pending some event that it is awaiting.  Prior to
+// returning, the task should acquire at least one |fit::suspended_task|
+// handle from its execution context using |fit::context::suspend_task()|
+// to provide a means for the task to be resumed once it can make forward
+// progress again.
+//
+// Once the suspended task is resumed with |fit::suspended_task::resume()|, it
+// is moved back to the ready queue and it will be invoked again during a later
+// iteration of the executor's loop.
+//
+// If all |fit::suspended_task| handles for a given task are destroyed without
+// the task ever being resumed then the task is also destroyed since there
+// would be no way for the task to be resumed from suspension.  We say that
+// such a task has been "abandoned".
+//
+// The executor retains single-ownership of all active and suspended tasks.
+// When the executor is destroyed, all of its remaining tasks are also
+// destroyed.
+//
+// Please read |fit::promise| for a more detailed explanation of the
+// responsibilities of tasks and executors.
+//
+// NOTES FOR IMPLEMENTORS
+//
+// This interface is designed to support a variety of different executor
+// implementations.  For example, one implementation might run its tasks on
+// a single thread whereas another might dispatch them on an event-driven
+// message loop or use a thread pool.
+//
+// See also |fit::single_threaded_executor| for a concrete implementation.
+class executor {
+public:
+    // Destroys the executor along with all of its remaining scheduled tasks
+    // that have yet to complete.
+    virtual ~executor() = default;
+
+    // Schedules a task for eventual execution by the executor.
+    //
+    // This method is thread-safe.
+    virtual void schedule_task(pending_task task) = 0;
+};
+
+// Represents a task that is awaiting resumption.
+//
+// This object has RAII semantics.  If the task is not resumed by at least
+// one holder of its |suspended_task| handles, then it will be destroyed
+// by the executor since it is no longer possible for the task to make
+// progress.  The task is said have been "abandoned".
+//
+// See documentation of |fit::executor| for more information.
+class suspended_task final {
+public:
+    // A handle that grants the capability to resume a suspended task.
+    // Each issued ticket must be individually resolved.
+    using ticket = uint64_t;
+
+    // The resolver mechanism implements a lightweight form of reference
+    // counting for tasks that have been suspended.
+    //
+    // When a suspended task is created in a non-empty state, it receives
+    // a pointer to a resolver interface and a ticket.  The ticket is
+    // a one-time-use handle that represents the task that was suspended
+    // and provides a means to resume it.  The |suspended_task| class ensures
+    // that every ticket is precisely accounted for.
+    //
+    // When |suspended_task::resume_task()| is called on an instance with
+    // a valid ticket, the resolver's |resolve_ticket()| method is invoked
+    // passing the ticket's value along with *true* to resume the task.  This
+    // operation consumes the ticket so the |suspended_task| transitions to
+    // an empty state.  The ticket and resolver cannot be used again by
+    // this |suspended_task| instance.
+    //
+    // Similarly, when |suspended_task::reset()| is called on an instance with
+    // a valid ticket or when the task goes out of scope on such an instance,
+    // the resolver's |resolve_ticket()| method is invoked but this time passes
+    // *false* to not resume the task.  As before, the ticket is consumed.
+    //
+    // Finally, when the |suspended_task| is copied, its ticket is duplicated
+    // using |duplicate_ticket()| resulting in two tickets, both of which
+    // must be individually resolved.
+    //
+    // Resuming a task that has already been resumed has no effect.
+    // Conversely, a task is considered "abandoned" if all of its tickets
+    // have been resolved without it ever being resumed.  See documentation
+    // of |fit::promise| for more information.
+    //
+    // The methods of this class are safe to call from any thread, including
+    // threads that may not be managed by the task's executor.
+    class resolver {
+    public:
+        // Duplicates the provided ticket, returning a new ticket.
+        // Note: The new ticket may have the same numeric value as the
+        //       original ticket but should be considered a distinct instance
+        //       that must be separately resolved.
+        virtual ticket duplicate_ticket(ticket ticket) = 0;
+
+        // Consumes the provided ticket, optionally resuming its associated task.
+        // The provided ticket must not be used again.
+        virtual void resolve_ticket(ticket ticket, bool resume_task) = 0;
+
+    protected:
+        virtual ~resolver() = default;
+    };
+
+    suspended_task()
+        : resolver_(nullptr), ticket_(0) {}
+
+    suspended_task(resolver* resolver, ticket ticket)
+        : resolver_(resolver), ticket_(ticket) {}
+
+    suspended_task(const suspended_task& other);
+    suspended_task(suspended_task&& other);
+
+    // Releases the task without resumption.
+    //
+    // Does nothing if this object does not hold a ticket.
+    ~suspended_task();
+
+    // Returns true if this object holds a ticket for a suspended task.
+    explicit operator bool() const { return resolver_ != nullptr; }
+
+    // Asks the task's executor to resume execution of the suspended task
+    // if it has not already been resumed or completed.  Also releases
+    // the task's ticket as a side-effect.
+    //
+    // Clients should call this method when it is possible for the task to
+    // make progress; for example, because some event the task was
+    // awaiting has occurred.  See documentation on |fit::executor|.
+    //
+    // Does nothing if this object does not hold a ticket.
+    void resume_task() { resolve(true); }
+
+    // Releases the suspended task without resumption.
+    //
+    // Does nothing if this object does not hold a ticket.
+    void reset() { resolve(false); }
+
+    suspended_task& operator=(const suspended_task& other);
+    suspended_task& operator=(suspended_task&& other);
+
+private:
+    void resolve(bool resume_task);
+
+    resolver* resolver_;
+    ticket ticket_;
+};
+
+} // namespace fit
+
+#endif // LIB_FIT_PROMISE_H_
diff --git a/pkg/fit/include/lib/fit/promise_internal.h b/pkg/fit/include/lib/fit/promise_internal.h
new file mode 100644
index 0000000..30e7085
--- /dev/null
+++ b/pkg/fit/include/lib/fit/promise_internal.h
@@ -0,0 +1,600 @@
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef LIB_FIT_PROMISE_INTERNAL_H_
+#define LIB_FIT_PROMISE_INTERNAL_H_
+
+#include <assert.h>
+
+#include <tuple>
+#include <type_traits>
+#include <utility>
+
+#include "function.h"
+#include "nullable.h"
+#include "result.h"
+#include "traits.h"
+
+namespace fit {
+
+template <typename Continuation>
+class promise_impl;
+
+template <typename Promise>
+class future_impl;
+
+class context;
+class executor;
+class suspended_task;
+
+namespace internal {
+
+// Determines whether a type is a kind of fit::result.
+template <typename Result>
+struct is_result : std::false_type {};
+template <typename V, typename E>
+struct is_result<::fit::result<V, E>> : std::true_type {};
+
+// Deduces a continuation's result.
+// Also ensures that the continuation has a compatible signature.
+template <typename Continuation,
+          typename = std::enable_if_t<is_result<
+              decltype(std::declval<Continuation&>()(
+                  std::declval<::fit::context&>()))>::value>>
+struct continuation_traits {
+    using type = Continuation;
+    using result_type = decltype(std::declval<Continuation&>()(std::declval<::fit::context&>()));
+};
+template <typename Continuation, typename = fit::void_t<>>
+struct is_continuation : std::false_type {};
+template <typename Continuation>
+struct is_continuation<
+    Continuation,
+    fit::void_t<typename continuation_traits<Continuation>::type>>
+    : std::true_type {};
+
+// Wraps a handler function and adapts its return type to a fit::result
+// via its specializations.
+template <typename Handler, typename DefaultV, typename DefaultE,
+          typename ReturnType = typename callable_traits<Handler>::return_type,
+          bool callable_result = ::fit::is_callable<ReturnType>::value>
+class result_adapter final {
+    // This expression always evaluates to false but depends on the template
+    // type parameters so that it only gets evaluated when the template is
+    // expanded.  If we simply wrote "false", the compiler would raise the
+    // static assertion failure as soon as it encountered the statement.
+    template <typename T>
+    struct check_result { static constexpr bool value = false; };
+    static_assert(
+        check_result<ReturnType>::value,
+        "The provided handler's result type was expected to be "
+        "fit::result<V, E>, fit::ok_result<V>, fit::error_result<E>, "
+        "fit::pending_result, void, or a continuation with the signature "
+        "fit::result<V, E>(fit::context&).  "
+        "Please refer to the combinator's documentation for a list of "
+        "supported handler function signatures.");
+};
+
+// Supports handlers that return void.
+template <typename Handler, typename DefaultV, typename DefaultE>
+class result_adapter<Handler, DefaultV, DefaultE, void, false> final {
+public:
+    using result_type = ::fit::result<DefaultV, DefaultE>;
+
+    explicit result_adapter(Handler handler)
+        : handler_(std::move(handler)) {}
+
+    template <typename... Args>
+    result_type call(::fit::context& context, Args... args) {
+        handler_(std::forward<Args>(args)...);
+        return ::fit::ok();
+    }
+
+private:
+    Handler handler_;
+};
+
+// Supports handlers that return pending_result.
+template <typename Handler, typename DefaultV, typename DefaultE>
+class result_adapter<Handler, DefaultV, DefaultE, ::fit::pending_result, false> final {
+public:
+    using result_type = ::fit::result<DefaultV, DefaultE>;
+
+    explicit result_adapter(Handler handler)
+        : handler_(std::move(handler)) {}
+
+    template <typename... Args>
+    result_type call(::fit::context& context, Args... args) {
+        return handler_(std::forward<Args>(args)...);
+    }
+
+private:
+    Handler handler_;
+};
+
+// Supports handlers that return ok_result<V>.
+template <typename Handler, typename DefaultV, typename DefaultE,
+          typename V>
+class result_adapter<Handler, DefaultV, DefaultE, ::fit::ok_result<V>, false> final {
+public:
+    using result_type = ::fit::result<V, DefaultE>;
+
+    explicit result_adapter(Handler handler)
+        : handler_(std::move(handler)) {}
+
+    template <typename... Args>
+    result_type call(::fit::context& context, Args... args) {
+        return handler_(std::forward<Args>(args)...);
+    }
+
+private:
+    Handler handler_;
+};
+
+// Supports handlers that return error_result<E>.
+template <typename Handler, typename DefaultV, typename DefaultE,
+          typename E>
+class result_adapter<Handler, DefaultV, DefaultE, ::fit::error_result<E>, false> final {
+public:
+    using result_type = ::fit::result<DefaultV, E>;
+
+    explicit result_adapter(Handler handler)
+        : handler_(std::move(handler)) {}
+
+    template <typename... Args>
+    result_type call(::fit::context& context, Args... args) {
+        return handler_(std::forward<Args>(args)...);
+    }
+
+private:
+    Handler handler_;
+};
+
+// Supports handlers that return result<V, E>.
+template <typename Handler, typename DefaultV, typename DefaultE,
+          typename V, typename E>
+class result_adapter<Handler, DefaultV, DefaultE, ::fit::result<V, E>, false> final {
+public:
+    using result_type = ::fit::result<V, E>;
+
+    explicit result_adapter(Handler handler)
+        : handler_(std::move(handler)) {}
+
+    template <typename... Args>
+    result_type call(::fit::context& context, Args... args) {
+        return handler_(std::forward<Args>(args)...);
+    }
+
+private:
+    Handler handler_;
+};
+
+// Supports handlers that return continuations or promises.
+// This works for any callable whose signature is:
+//     fit::result<...>(fit::context&)
+template <typename Handler, typename DefaultV, typename DefaultE,
+          typename ReturnType>
+class result_adapter<Handler, DefaultV, DefaultE, ReturnType, true> final {
+    // If the handler doesn't actually return a continuation then the
+    // compilation will fail here which is slightly easier to diagnose
+    // than if we dropped the result_adapter specialization entirely.
+    using continuation_traits = continuation_traits<ReturnType>;
+    using continuation_type = typename continuation_traits::type;
+
+public:
+    using result_type = typename continuation_traits::result_type;
+
+    explicit result_adapter(Handler handler)
+        : handler_(std::move(handler)) {}
+
+    template <typename... Args>
+    result_type call(::fit::context& context, Args... args) {
+        if (handler_) {
+            continuation_ = (*handler_)(std::forward<Args>(args)...);
+            handler_.reset();
+        }
+        if (!continuation_) {
+            return ::fit::pending();
+        }
+        return (*continuation_)(context);
+    }
+
+private:
+    ::fit::nullable<Handler> handler_;
+    ::fit::nullable<continuation_type> continuation_;
+};
+
+// Wraps a handler that may or may not have a fit::context& as first argument.
+// This is determined by checking the argument count.
+template <typename Handler, typename DefaultV, typename DefaultE,
+          size_t num_args = 0,
+          int excess_args =
+              (static_cast<int>(
+                   ::fit::callable_traits<Handler>::args::size) -
+               static_cast<int>(num_args))>
+class context_adapter final {
+    static_assert(
+        excess_args >= 0,
+        "The provided handler has too few arguments.  "
+        "Please refer to the combinator's documentation for a list of "
+        "supported handler function signatures.");
+    static_assert(
+        excess_args <= 1,
+        "The provided handler has too many arguments.  "
+        "Please refer to the combinator's documentation for a list of "
+        "supported handler function signatures.");
+};
+
+// Supports handlers without a context argument.
+template <typename Handler, typename DefaultV, typename DefaultE,
+          size_t num_args>
+class context_adapter<Handler, DefaultV, DefaultE, num_args, 0> final {
+    using base_type = result_adapter<Handler, DefaultV, DefaultE>;
+
+public:
+    using result_type = typename base_type::result_type;
+    static constexpr size_t next_arg_index = 0;
+
+    explicit context_adapter(Handler handler)
+        : base_(std::move(handler)) {}
+
+    template <typename... Args>
+    result_type call(::fit::context& context, Args... args) {
+        return base_.template call<Args...>(context, std::forward<Args>(args)...);
+    }
+
+private:
+    base_type base_;
+};
+
+// Supports handlers with a context argument.
+template <typename Handler, typename DefaultV, typename DefaultE,
+          size_t num_args>
+class context_adapter<Handler, DefaultV, DefaultE, num_args, 1> final {
+    using base_type = result_adapter<Handler, DefaultV, DefaultE>;
+    using context_arg_type =
+        typename ::fit::callable_traits<Handler>::args::template at<0>;
+    static_assert(
+        std::is_same<context_arg_type, ::fit::context&>::value,
+        "The provided handler's first argument was expected to be of type "
+        "fit::context& based on the number of arguments it has.  "
+        "Please refer to the combinator's documentation for a list of "
+        "supported handler function signatures.");
+
+public:
+    using result_type = typename base_type::result_type;
+    static constexpr size_t next_arg_index = 1;
+
+    explicit context_adapter(Handler handler)
+        : base_(std::move(handler)) {}
+
+    template <typename... Args>
+    result_type call(::fit::context& context, Args... args) {
+        return base_.template call<::fit::context&, Args...>(
+            context, context, std::forward<Args>(args)...);
+    }
+
+private:
+    base_type base_;
+};
+
+// Wraps a handler that may accept a context argument.
+template <typename Handler>
+class context_handler_invoker final {
+    using base_type = context_adapter<Handler, void, void, 0>;
+
+public:
+    using result_type = typename base_type::result_type;
+
+    explicit context_handler_invoker(Handler handler)
+        : base_(std::move(handler)) {}
+
+    result_type operator()(::fit::context& context) {
+        return base_.template call<>(context);
+    }
+
+private:
+    base_type base_;
+};
+
+// Wraps a handler that may accept a context and result argument.
+template <typename Handler, typename PriorResult>
+class result_handler_invoker final {
+    using base_type = context_adapter<Handler, void, void, 1>;
+    using result_arg_type =
+        typename ::fit::callable_traits<Handler>::args::template at<
+            base_type::next_arg_index>;
+    static_assert(
+        (std::is_same<result_arg_type, PriorResult>::value &&
+         std::is_copy_constructible<result_arg_type>::value) ||
+            std::is_same<result_arg_type, PriorResult&>::value ||
+            std::is_same<result_arg_type, const PriorResult&>::value,
+        "The provided handler's last argument was expected to be of type "
+        "fit::result<V, E>&, const fit::result<V, E>&, or fit::result<V, E> "
+        "(if the result is copy-constructible).  "
+        "Please refer to the combinator's documentation for a list of "
+        "supported handler function signatures.");
+
+public:
+    using result_type = typename base_type::result_type;
+
+    explicit result_handler_invoker(Handler handler)
+        : base_(std::move(handler)) {}
+
+    result_type operator()(::fit::context& context, PriorResult& result) {
+        return base_.template call<PriorResult&>(context, result);
+    }
+
+private:
+    base_type base_;
+};
+
+// Wraps a handler that may accept a context and value argument.
+template <typename Handler, typename PriorResult,
+          typename V = typename PriorResult::value_type>
+class value_handler_invoker final {
+    using base_type = context_adapter<Handler,
+                                      void, typename PriorResult::error_type, 1>;
+    using value_arg_type =
+        typename ::fit::callable_traits<Handler>::args::template at<
+            base_type::next_arg_index>;
+    static_assert(
+        (std::is_same<value_arg_type, V>::value &&
+         std::is_copy_constructible<value_arg_type>::value) ||
+            std::is_same<value_arg_type, V&>::value ||
+            std::is_same<value_arg_type, const V&>::value,
+        "The provided handler's last argument was expected to be of type "
+        "V&, const V&, or V (if the value is copy-constructible).  "
+        "Please refer to the combinator's documentation for a list of "
+        "supported handler function signatures.");
+
+public:
+    using result_type = typename base_type::result_type;
+
+    explicit value_handler_invoker(Handler handler)
+        : base_(std::move(handler)) {}
+
+    result_type operator()(::fit::context& context, PriorResult& result) {
+        return base_.template call<V&>(context, result.value());
+    }
+
+private:
+    base_type base_;
+};
+
+// Specialization for void value.
+template <typename Handler, typename PriorResult>
+class value_handler_invoker<Handler, PriorResult, void> final {
+    using base_type = context_adapter<Handler,
+                                      void, typename PriorResult::error_type, 0>;
+
+public:
+    using result_type = typename base_type::result_type;
+
+    explicit value_handler_invoker(Handler handler)
+        : base_(std::move(handler)) {}
+
+    result_type operator()(::fit::context& context, PriorResult& result) {
+        return base_.template call<>(context);
+    }
+
+private:
+    base_type base_;
+};
+
+// Wraps a handler that may accept a context and error argument.
+template <typename Handler, typename PriorResult,
+          typename E = typename PriorResult::error_type>
+class error_handler_invoker final {
+    using base_type = context_adapter<Handler,
+                                      typename PriorResult::value_type, void, 1>;
+    using error_arg_type =
+        typename ::fit::callable_traits<Handler>::args::template at<
+            base_type::next_arg_index>;
+    static_assert(
+        (std::is_same<error_arg_type, E>::value &&
+         std::is_copy_constructible<error_arg_type>::value) ||
+            std::is_same<error_arg_type, E&>::value ||
+            std::is_same<error_arg_type, const E&>::value,
+        "The provided handler's last argument was expected to be of type "
+        "E&, const E&, or E (if the error is copy-constructible).  "
+        "Please refer to the combinator's documentation for a list of "
+        "supported handler function signatures.");
+
+public:
+    using result_type = typename base_type::result_type;
+
+    explicit error_handler_invoker(Handler handler)
+        : base_(std::move(handler)) {}
+
+    result_type operator()(::fit::context& context, PriorResult& result) {
+        return base_.template call<E&>(context, result.error());
+    }
+
+private:
+    base_type base_;
+};
+
+// Specialization for void error.
+template <typename Handler, typename PriorResult>
+class error_handler_invoker<Handler, PriorResult, void> final {
+    using base_type = context_adapter<Handler,
+                                      typename PriorResult::value_type, void, 0>;
+
+public:
+    using result_type = typename base_type::result_type;
+
+    explicit error_handler_invoker(Handler handler)
+        : base_(std::move(handler)) {}
+
+    result_type operator()(::fit::context& context, PriorResult& result) {
+        return base_.template call<>(context);
+    }
+
+private:
+    base_type base_;
+};
+
+// The continuation produced by |fit::promise::then()|.
+template <typename PriorPromise, typename ResultHandler>
+class then_continuation final {
+    using invoker_type = ::fit::internal::result_handler_invoker<
+        ResultHandler, typename PriorPromise::result_type>;
+
+public:
+    then_continuation(PriorPromise prior_promise, ResultHandler handler)
+        : prior_(std::move(prior_promise)),
+          invoker_(std::move(handler)) {}
+
+    typename invoker_type::result_type operator()(::fit::context& context) {
+        if (!prior_(context))
+            return ::fit::pending();
+        return invoker_(context, prior_.result());
+    }
+
+private:
+    future_impl<PriorPromise> prior_;
+    invoker_type invoker_;
+};
+
+// The continuation produced by |fit::promise::and_then()|.
+template <typename PriorPromise, typename ValueHandler>
+class and_then_continuation final {
+    using invoker_type = ::fit::internal::value_handler_invoker<
+        ValueHandler, typename PriorPromise::result_type>;
+
+public:
+    and_then_continuation(PriorPromise prior_promise, ValueHandler handler)
+        : prior_(std::move(prior_promise)),
+          invoker_(std::move(handler)) {}
+
+    typename invoker_type::result_type operator()(::fit::context& context) {
+        if (!prior_(context))
+            return ::fit::pending();
+        if (prior_.is_error())
+            return prior_.take_error_result();
+        return invoker_(context, prior_.result());
+    }
+
+private:
+    future_impl<PriorPromise> prior_;
+    invoker_type invoker_;
+};
+
+// The continuation produced by |fit::promise::or_else()|.
+template <typename PriorPromise, typename ErrorHandler>
+class or_else_continuation final {
+    using invoker_type = ::fit::internal::error_handler_invoker<
+        ErrorHandler, typename PriorPromise::result_type>;
+
+public:
+    or_else_continuation(PriorPromise prior_promise, ErrorHandler handler)
+        : prior_(std::move(prior_promise)),
+          invoker_(std::move(handler)) {}
+
+    typename invoker_type::result_type operator()(::fit::context& context) {
+        if (!prior_(context))
+            return ::fit::pending();
+        if (prior_.is_ok())
+            return prior_.take_ok_result();
+        return invoker_(context, prior_.result());
+    }
+
+private:
+    future_impl<PriorPromise> prior_;
+    invoker_type invoker_;
+};
+
+// The continuation produced by |fit::promise::inspect()|.
+template <typename PriorPromise, typename InspectHandler>
+class inspect_continuation final {
+    using invoker_type = ::fit::internal::result_handler_invoker<
+        InspectHandler, typename PriorPromise::result_type>;
+
+public:
+    inspect_continuation(PriorPromise prior_promise, InspectHandler handler)
+        : prior_(std::move(prior_promise)),
+          invoker_(std::move(handler)) {}
+
+    typename PriorPromise::result_type operator()(::fit::context& context) {
+        typename PriorPromise::result_type result = prior_(context);
+        if (result)
+            invoker_(context, result);
+        return result;
+    }
+
+private:
+    PriorPromise prior_;
+    invoker_type invoker_;
+};
+
+// The continuation produced by |fit::promise::discard_result()|.
+template <typename PriorPromise>
+class discard_result_continuation final {
+public:
+    explicit discard_result_continuation(PriorPromise prior_promise)
+        : prior_(std::move(prior_promise)) {}
+
+    fit::result<> operator()(::fit::context& context) {
+        if (!prior_(context))
+            return ::fit::pending();
+        return ::fit::ok();
+    }
+
+private:
+    PriorPromise prior_;
+};
+
+// The continuation produced by |make_promise()|.
+// This turns out to be equivalent to a context handler invoker.
+template <typename PromiseHandler>
+using promise_continuation = context_handler_invoker<PromiseHandler>;
+
+// Returns true if all arguments are true or if there are none.
+inline bool all_true() {
+    return true;
+}
+template <typename... Ts>
+inline bool all_true(bool value, Ts... values) {
+    return value & all_true(values...);
+}
+
+// The continuation produced by |join_promises()|.
+template <typename... Promises>
+class join_continuation final {
+public:
+    explicit join_continuation(Promises... promises)
+        : promises_(std::make_tuple(std::move(promises)...)) {}
+
+    ::fit::result<std::tuple<typename Promises::result_type...>> operator()(
+        ::fit::context& context) {
+        return evaluate(context, std::index_sequence_for<Promises...>{});
+    }
+
+private:
+    template <size_t... i>
+    ::fit::result<std::tuple<typename Promises::result_type...>> evaluate(
+        ::fit::context& context, std::index_sequence<i...>) {
+        bool done = all_true(std::get<i>(promises_)(context)...);
+        if (!done)
+            return ::fit::pending();
+        return ::fit::ok(std::make_tuple(std::get<i>(promises_).take_result()...));
+    }
+
+    std::tuple<future_impl<Promises>...> promises_;
+};
+
+} // namespace internal
+
+template <typename PromiseHandler>
+inline promise_impl<::fit::internal::promise_continuation<PromiseHandler>>
+make_promise(PromiseHandler handler);
+
+template <typename Continuation>
+inline promise_impl<Continuation> make_promise_with_continuation(
+    Continuation continuation);
+
+} // namespace fit
+
+#endif // LIB_FIT_PROMISE_INTERNAL_H_
diff --git a/pkg/fit/include/lib/fit/result.h b/pkg/fit/include/lib/fit/result.h
new file mode 100644
index 0000000..eb89baf
--- /dev/null
+++ b/pkg/fit/include/lib/fit/result.h
@@ -0,0 +1,270 @@
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef LIB_FIT_RESULT_H_
+#define LIB_FIT_RESULT_H_
+
+#include <assert.h>
+
+#include <new>
+#include <type_traits>
+#include <utility>
+
+#include "traits.h"
+#include "variant.h"
+
+namespace fit {
+
+// Represents the intermediate state of a result that has not yet completed.
+struct pending_result final {};
+
+// Returns an value that represents a pending result.
+constexpr inline pending_result pending() {
+    return pending_result{};
+}
+
+// Represents the result of a successful task.
+template <typename V = void>
+struct ok_result final {
+    using value_type = V;
+
+    explicit constexpr ok_result(V value)
+        : value(std::move(value)) {}
+
+    V value;
+};
+template <>
+struct ok_result<void> {
+    using value_type = void;
+};
+
+// Wraps the result of a successful task as an |ok_result<T>|.
+template <typename V>
+constexpr inline ok_result<V> ok(V value) {
+    return ok_result<V>(std::move(value));
+}
+constexpr inline ok_result<> ok() {
+    return ok_result<>{};
+}
+
+// Represents the result of a failed task.
+template <typename E = void>
+struct error_result final {
+    using error_type = E;
+
+    explicit constexpr error_result(E error)
+        : error(std::move(error)) {}
+
+    E error;
+};
+template <>
+struct error_result<void> {
+    using error_type = void;
+};
+
+// Wraps the result of a failed task as an |error_result<T>|.
+template <typename E>
+constexpr inline error_result<E> error(E error) {
+    return error_result<E>(std::move(error));
+}
+constexpr inline error_result<> error() {
+    return error_result<>{};
+}
+
+// Describes the status of a task's result.
+enum class result_state {
+    // The task is still in progress.
+    pending,
+    // The task completed successfully.
+    ok,
+    // The task failed.
+    error
+};
+
+// Represents the result of a task which may have succeeded, failed,
+// or still be in progress.
+//
+// Use |fit::pending()|, |fit::ok<T>()|, or |fit::error<T>| to initialize
+// the result.
+//
+// |V| is the type of value produced when the completes successfully.
+// Defaults to |void|.
+//
+// |E| is the type of error produced when the completes with an error.
+// Defaults to |void|.
+//
+// EXAMPLE:
+//
+// fit::result<int, std::string> divide(int dividend, int divisor) {
+//     if (divisor == 0)
+//         return fit::error<std::string>("divide by zero");
+//     return fit::ok(dividend / divisor);
+// }
+//
+// int try_divide(int dividend, int divisor) {
+//     auto result = divide(dividend, divisor);
+//     if (result.is_ok()) {
+//         printf("%d / %d = %d\n", dividend, divisor, result.value());
+//         return result.value();
+//     }
+//     printf("%d / %d: ERROR %s\n", dividend, divisor, result.error().c_str());
+//     return -999;
+// }
+//
+// EXAMPLE WITH VOID RESULT VALUE AND ERROR:
+//
+// fit::result<> open(std::string secret) {
+//     printf("guessing \"%s\"\n", secret.c_str());
+//     if (secret == "sesame") {
+//         return fit::ok();
+//         puts("yes!");
+//     }
+//     puts("no.");
+//     return fit::error();
+// }
+//
+// bool guess_combination() {
+//     return open("friend") || open("sesame") || open("I give up");
+// }
+template <typename V = void, typename E = void>
+class result final {
+public:
+    using value_type = V;
+    using error_type = E;
+
+    // Creates a pending result.
+    constexpr result() = default;
+    constexpr result(pending_result) {}
+
+    // Creates an ok result.
+    constexpr result(ok_result<V> result)
+        : state_(::fit::internal::in_place_index<1>, std::move(result)) {}
+    template <typename OtherV,
+              typename = std::enable_if_t<std::is_constructible<V, OtherV>::value>>
+    constexpr result(ok_result<OtherV> other)
+        : state_(::fit::internal::in_place_index<1>,
+                 fit::ok<V>(std::move(other.value))) {}
+
+    // Creates an error result.
+    constexpr result(error_result<E> result)
+        : state_(::fit::internal::in_place_index<2>, std::move(result)) {}
+    template <typename OtherE,
+              typename = std::enable_if_t<std::is_constructible<E, OtherE>::value>>
+    constexpr result(error_result<OtherE> other)
+        : state_(::fit::internal::in_place_index<2>,
+                 fit::error<E>(std::move(other.error))) {}
+
+    // Copies another result (if copyable).
+    result(const result& other) = default;
+
+    // Moves from another result, leaving the other one in a pending state.
+    result(result&& other)
+        : state_(std::move(other.state_)) {
+        other.reset();
+    }
+
+    ~result() = default;
+
+    // Returns the state of the task's result: pending, ok, or error.
+    constexpr result_state state() const {
+        return static_cast<result_state>(state_.index());
+    }
+
+    // Returns true if the result is not pending.
+    constexpr explicit operator bool() const {
+        return !is_pending();
+    }
+
+    // Returns true if the task is still in progress.
+    constexpr bool is_pending() const {
+        return state() == result_state::pending;
+    }
+
+    // Returns true if the task succeeded.
+    constexpr bool is_ok() const {
+        return state() == result_state::ok;
+    }
+
+    // Returns true if the task failed.
+    constexpr bool is_error() const {
+        return state() == result_state::error;
+    }
+
+    // Gets the result's value.
+    // Asserts that the result's state is |fit::result_state::ok|.
+    template <typename R = V,
+              typename = std::enable_if_t<!std::is_void<R>::value>>
+    constexpr R& value() {
+        return state_.template get<1>().value;
+    }
+    template <typename R = V,
+              typename = std::enable_if_t<!std::is_void<R>::value>>
+    constexpr const R& value() const {
+        return state_.template get<1>().value;
+    }
+
+    // Takes the result's value, leaving it in a pending state.
+    // Asserts that the result's state is |fit::result_state::ok|.
+    template <typename R = V,
+              typename = std::enable_if_t<!std::is_void<R>::value>>
+    R take_value() {
+        auto value = std::move(state_.template get<1>().value);
+        reset();
+        return value;
+    }
+    ok_result<V> take_ok_result() {
+        auto result = std::move(state_.template get<1>());
+        reset();
+        return result;
+    }
+
+    // Gets a reference to the result's error.
+    // Asserts that the result's state is |fit::result_state::error|.
+    template <typename R = E,
+              typename = std::enable_if_t<!std::is_void<R>::value>>
+    constexpr R& error() {
+        return state_.template get<2>().error;
+    }
+    template <typename R = E,
+              typename = std::enable_if_t<!std::is_void<R>::value>>
+    constexpr const R& error() const {
+        return state_.template get<2>().error;
+    }
+
+    // Takes the result's error, leaving it in a pending state.
+    // Asserts that the result's state is |fit::result_state::error|.
+    template <typename R = E,
+              typename = std::enable_if_t<!std::is_void<R>::value>>
+    R take_error() {
+        auto error = std::move(state_.template get<2>().error);
+        reset();
+        return error;
+    }
+    error_result<E> take_error_result() {
+        auto result = std::move(state_.template get<2>());
+        reset();
+        return result;
+    }
+
+    // Assigns from another result (if copyable).
+    result& operator=(const result& other) = default;
+
+    // Moves from another result, leaving the other one in a pending state.
+    result& operator=(result&& other) {
+        state_ = std::move(other.state_);
+        other.reset();
+        return *this;
+    }
+
+private:
+    void reset() { state_.template emplace<0>(); }
+
+    ::fit::internal::variant<
+        ::fit::internal::monostate, ok_result<V>, error_result<E>>
+        state_;
+};
+
+} // namespace fit
+
+#endif // LIB_FIT_RESULT_H_
diff --git a/pkg/fit/include/lib/fit/scheduler.h b/pkg/fit/include/lib/fit/scheduler.h
new file mode 100644
index 0000000..d4e16ba
--- /dev/null
+++ b/pkg/fit/include/lib/fit/scheduler.h
@@ -0,0 +1,154 @@
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef LIB_FIT_SCHEDULER_H_
+#define LIB_FIT_SCHEDULER_H_
+
+#include <map>
+#include <queue>
+#include <utility>
+
+#include "promise.h"
+
+namespace fit {
+namespace subtle {
+
+// Keeps track of runnable and suspended tasks.
+// This is a low-level building block for implementing executors.
+// For a concrete implementation, see |fit::single_threaded_executor|.
+//
+// Instances of this object are not thread-safe.  Its client is responsible
+// for providing all necessary synchronization.
+class scheduler final {
+public:
+    using task_queue = std::queue<pending_task>;
+    using ref_count = uint32_t;
+
+    scheduler();
+    ~scheduler();
+
+    // Adds a task to the runnable queue.
+    //
+    // Preconditions:
+    // - |task| must be non-empty
+    void schedule_task(pending_task task);
+
+    // Obtains a new ticket with a ref-count of |initial_refs|.
+    // The executor must eventually call |finalize_ticket()| to update the
+    // state of the ticket.
+    //
+    // Preconditions:
+    // - |initial_refs| must be at least 1
+    suspended_task::ticket obtain_ticket(ref_count initial_refs = 1);
+
+    // Updates a ticket after one run of a task's continuation according
+    // to the state of the task after its run.  The executor must call this
+    // method after calling |obtain_ticket()| to indicate the disposition of
+    // the task for which the ticket was obtained.
+    //
+    // Passing an empty |task| indicates that the task has completed so it
+    // does not need to be resumed.
+    //
+    // Passing a non-empty |task| indicates that the task returned a pending
+    // result and may need to be suspended depending on the current state
+    // of the ticket.
+    // - If the ticket has already been resumed, moves |task| into the
+    //   runnable queue.
+    // - Otherwise, if the ticket still has a non-zero ref-count, moves |task|
+    //   into the suspended task table.
+    // - Otherwise, considers the task abandoned and the caller retains
+    //   ownership of |task|.
+    //
+    // Preconditions:
+    // - |task| must be non-null (may be empty)
+    // - the ticket must not have already been finalized
+    void finalize_ticket(suspended_task::ticket ticket, pending_task* task);
+
+    // Increments the ticket's ref-count.
+    //
+    // Preconditions:
+    // - the ticket's ref-count must be non-zero (positive)
+    void duplicate_ticket(suspended_task::ticket ticket);
+
+    // Decrements the ticket's ref-count.
+    //
+    // If the task's ref-count reaches 0 and has an associated task that
+    // has not already been resumed, returns the associated task back
+    // to the caller.
+    // Otherwise, returns an empty task.
+    //
+    // Preconditions:
+    // - the ticket's ref-count must be non-zero (positive)
+    pending_task release_ticket(suspended_task::ticket ticket);
+
+    // Resumes a task and decrements the ticket's ref-count.
+    //
+    // If the ticket has an associated task that has not already been resumed,
+    // moves its associated task to the runnable queue and returns true.
+    // Otherwise, returns false.
+    //
+    // Preconditions:
+    // - the ticket's ref-count must be non-zero (positive)
+    bool resume_task_with_ticket(suspended_task::ticket ticket);
+
+    // Takes all tasks in the runnable queue.
+    //
+    // Preconditions:
+    // - |tasks| must be non-null and empty
+    void take_runnable_tasks(task_queue* tasks);
+
+    // Takes all remaining tasks, regardless of whether they are runnable
+    // or suspended.
+    //
+    // This operation is useful when shutting down an executor.
+    //
+    // Preconditions:
+    // - |tasks| must be non-null and empty
+    void take_all_tasks(task_queue* tasks);
+
+    // Returns true if there are any runnable tasks.
+    bool has_runnable_tasks() const { return !runnable_tasks_.empty(); }
+
+    // Returns true if there are any suspended tasks that have yet to
+    // be resumed.
+    bool has_suspended_tasks() const { return suspended_task_count_ > 0; }
+
+    // Returns true if there are any tickets that have yet to be finalized,
+    // released, or resumed.
+    bool has_outstanding_tickets() const { return !tickets_.empty(); }
+
+    scheduler(const scheduler&) = delete;
+    scheduler(scheduler&&) = delete;
+    scheduler& operator=(const scheduler&) = delete;
+    scheduler& operator=(scheduler&&) = delete;
+
+private:
+    struct ticket_record {
+        ticket_record(ref_count initial_refs)
+            : ref_count(initial_refs), was_resumed(false) {}
+
+        // The current reference count.
+        ref_count ref_count;
+
+        // True if the task has been resumed using |resume_task_with_ticket()|.
+        bool was_resumed;
+
+        // The task is initially empty when the ticket is obtained.
+        // It is later set to non-empty if the task needs to be suspended when
+        // the ticket is finalized.  It becomes empty again when the task
+        // is moved into the runnable queue, released, or taken.
+        pending_task task;
+    };
+    using ticket_map = std::map<suspended_task::ticket, ticket_record>;
+
+    task_queue runnable_tasks_;
+    ticket_map tickets_;
+    uint64_t suspended_task_count_ = 0;
+    suspended_task::ticket next_ticket_ = 1;
+};
+
+} // namespace subtle
+} // namespace fit
+
+#endif // LIB_FIT_SCHEDULER_H_
diff --git a/pkg/fit/include/lib/fit/sequencer.h b/pkg/fit/include/lib/fit/sequencer.h
new file mode 100644
index 0000000..509cd8e
--- /dev/null
+++ b/pkg/fit/include/lib/fit/sequencer.h
@@ -0,0 +1,85 @@
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef LIB_FIT_SEQUENCER_H_
+#define LIB_FIT_SEQUENCER_H_
+
+#include <assert.h>
+
+#include <mutex>
+
+#include "bridge.h"
+#include "thread_safety.h"
+
+namespace fit {
+
+// A sequencer imposes a first-in-first-out sequential execution order onto a
+// sequence of promises.  Each successively enqueued promise remains suspended
+// until all previously enqueued promises complete or are abandoned.
+//
+// |fit::sequencer| is designed to be used either on its own or chained
+// onto a promise using |fit::promise::wrap_with()|.
+//
+// EXAMPLE
+//
+//     // This wrapper type is intended to be applied to
+//     // a sequence of promises so we store it in a variable.
+//     fit::sequencer seq;
+//
+//     // This task consists of some amount of work that must be
+//     // completed sequentially followed by other work that can
+//     // happen in any order.  We use |wrap_with()| to wrap the
+//     // sequential work with the sequencer.
+//     fit::promise<> perform_complex_task() {
+//         return fit::make_promise([] { /* do sequential work */ })
+//             .then([] (fit::result<> result) { /* this will also be wrapped */ })
+//             .wrap_with(seq)
+//             .then([] (fit::result<> result) { /* do more work */ });
+//     }
+//
+class sequencer final {
+public:
+    sequencer();
+    ~sequencer();
+
+    // Returns a new promise which will invoke |promise| after all previously
+    // enqueued promises on this sequencer have completed or been abandoned.
+    //
+    // This method is thread-safe.
+    template <typename Promise>
+    decltype(auto) wrap(Promise promise) {
+        assert(promise);
+
+        fit::bridge<> bridge;
+        fit::consumer<> prior = swap_prior(std::move(bridge.consumer()));
+        return prior.promise_or(fit::ok())
+            .then([promise = std::move(promise),
+                   completer = std::move(bridge.completer())](
+                      fit::context& context, fit::result<>) mutable {
+                // This handler will run once the completer associated
+                // with the |prior| promise is abandoned.  Once the promise
+                // has finished, both the promise and completer will be
+                // destroyed thereby causing the next promise chained onto
+                // the |bridge|'s associated consumer to become runnable.
+                return promise(context);
+            });
+    }
+
+    sequencer(const sequencer&) = delete;
+    sequencer(sequencer&&) = delete;
+    sequencer& operator=(const sequencer&) = delete;
+    sequencer& operator=(sequencer&&) = delete;
+
+private:
+    fit::consumer<> swap_prior(fit::consumer<> new_prior);
+
+    std::mutex mutex_;
+
+    // Holds the consumption capability of the most recently wrapped promise.
+    fit::consumer<> prior_ FIT_GUARDED(mutex_);
+};
+
+} // namespace fit
+
+#endif // LIB_FIT_SEQUENCER_H_
diff --git a/pkg/fit/include/lib/fit/single_threaded_executor.h b/pkg/fit/include/lib/fit/single_threaded_executor.h
new file mode 100644
index 0000000..7ec4875
--- /dev/null
+++ b/pkg/fit/include/lib/fit/single_threaded_executor.h
@@ -0,0 +1,85 @@
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef LIB_FIT_SINGLE_THREADED_EXECUTOR_H_
+#define LIB_FIT_SINGLE_THREADED_EXECUTOR_H_
+
+#include <utility>
+
+#include "promise.h"
+#include "scheduler.h"
+
+namespace fit {
+
+// A simple platform-independent single-threaded asynchronous task executor.
+//
+// This implementation is designed for use when writing simple single-threaded
+// platform-independent applications.  It may be less efficient or provide
+// fewer features than more specialized or platform-dependent executors.
+//
+// See documentation of |fit::promise| for more information.
+class single_threaded_executor final : public executor {
+public:
+    single_threaded_executor();
+
+    // Destroys the executor along with all of its remaining scheduled tasks
+    // that have yet to complete.
+    ~single_threaded_executor() override;
+
+    // Schedules a task for eventual execution by the executor.
+    //
+    // This method is thread-safe.
+    void schedule_task(pending_task task) override;
+
+    // Runs all scheduled tasks (including additional tasks scheduled while
+    // they run) until none remain.
+    //
+    // This method is thread-safe but must only be called on at most one
+    // thread at a time.
+    void run();
+
+    single_threaded_executor(const single_threaded_executor&) = delete;
+    single_threaded_executor(single_threaded_executor&&) = delete;
+    single_threaded_executor& operator=(const single_threaded_executor&) = delete;
+    single_threaded_executor& operator=(single_threaded_executor&&) = delete;
+
+private:
+    class dispatcher_impl;
+
+    // The task context for tasks run by the executor.
+    class context_impl final : public context {
+    public:
+        explicit context_impl(single_threaded_executor* executor);
+        ~context_impl() override;
+
+        single_threaded_executor* executor() const override;
+        suspended_task suspend_task() override;
+
+    private:
+        single_threaded_executor* const executor_;
+    };
+
+    context_impl context_;
+    dispatcher_impl* const dispatcher_;
+};
+
+// Creates a new |fit::single_threaded_executor|, schedules a promise as a task,
+// runs all of the executor's scheduled tasks until none remain, then returns
+// the promise's result.
+template <typename Continuation>
+static typename promise_impl<Continuation>::result_type
+run_single_threaded(promise_impl<Continuation> promise) {
+    using result_type = typename promise_impl<Continuation>::result_type;
+    single_threaded_executor exec;
+    result_type saved_result;
+    exec.schedule_task(promise.then([&saved_result](result_type result) {
+        saved_result = std::move(result);
+    }));
+    exec.run();
+    return saved_result;
+}
+
+} // namespace fit
+
+#endif // LIB_FIT_SINGLE_THREADED_EXECUTOR_H_
diff --git a/pkg/fit/include/lib/fit/thread_safety.h b/pkg/fit/include/lib/fit/thread_safety.h
new file mode 100644
index 0000000..8ffc5ad
--- /dev/null
+++ b/pkg/fit/include/lib/fit/thread_safety.h
@@ -0,0 +1,30 @@
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef LIB_FIT_THREAD_SAFETY_H_
+#define LIB_FIT_THREAD_SAFETY_H_
+
+// Thread-safety annotations.
+// Currently these are only supported on Clang.
+#if defined(__clang__) &&                                \
+    defined(_LIBCPP_ENABLE_THREAD_SAFETY_ANNOTATIONS) && \
+    __has_attribute(acquire_capability)
+#define FIT_THREAD_ANNOTATION(x) __attribute__((x))
+#else
+#define FIT_THREAD_ANNOTATION(x)
+#endif
+#define FIT_CAPABILITY(x) FIT_THREAD_ANNOTATION(__capability__(x))
+#define FIT_GUARDED(x) FIT_THREAD_ANNOTATION(__guarded_by__(x))
+#define FIT_ACQUIRE(...) FIT_THREAD_ANNOTATION(__acquire_capability__(__VA_ARGS__))
+#define FIT_TRY_ACQUIRE(...) FIT_THREAD_ANNOTATION(__try_acquire_capability__(__VA_ARGS__))
+#define FIT_ACQUIRED_BEFORE(...) FIT_THREAD_ANNOTATION(__acquired_before__(__VA_ARGS__))
+#define FIT_ACQUIRED_AFTER(...) FIT_THREAD_ANNOTATION(__acquired_after__(__VA_ARGS__))
+#define FIT_RELEASE(...) FIT_THREAD_ANNOTATION(__release_capability__(__VA_ARGS__))
+#define FIT_REQUIRES(...) FIT_THREAD_ANNOTATION(__requires_capability__(__VA_ARGS__))
+#define FIT_EXCLUDES(...) FIT_THREAD_ANNOTATION(__locks_excluded__(__VA_ARGS__))
+#define FIT_RETURN_CAPABILITY(x) FIT_THREAD_ANNOTATION(__lock_returned__(x))
+#define FIT_SCOPED_CAPABILITY FIT_THREAD_ANNOTATION(__scoped_lockable__)
+#define FIT_NO_THREAD_SAFETY_ANALYSIS FIT_THREAD_ANNOTATION(__no_thread_safety_analysis__)
+
+#endif // LIB_FIT_THREAD_SAFETY_H_
diff --git a/pkg/fit/include/lib/fit/traits.h b/pkg/fit/include/lib/fit/traits.h
new file mode 100644
index 0000000..933005e
--- /dev/null
+++ b/pkg/fit/include/lib/fit/traits.h
@@ -0,0 +1,110 @@
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef LIB_FIT_TRAITS_H_
+#define LIB_FIT_TRAITS_H_
+
+#include <tuple>
+#include <type_traits>
+
+namespace fit {
+
+// C++ 14 compatible implementation of std::void_t.
+#if defined(__cplusplus) && __cplusplus >= 201703L
+template <typename... T>
+using void_t = std::void_t<T...>;
+#else
+template <typename... T>
+struct make_void { typedef void type; };
+template <typename... T>
+using void_t = typename make_void<T...>::type;
+#endif
+
+// Encapsulates capture of a parameter pack. Typical use is to use instances of this empty struct
+// for type dispatch in function template deduction/overload resolution.
+//
+// Example:
+//  template <typename Callable, typename... Args>
+//  auto inspect_args(Callable c, parameter_pack<Args...>) {
+//      // do something with Args...
+//  }
+//
+//  template <typename Callable>
+//  auto inspect_args(Callable c) {
+//      return inspect_args(std::move(c), typename callable_traits<Callable>::args{});
+//  }
+template <typename... T>
+struct parameter_pack {
+    static constexpr size_t size = sizeof...(T);
+
+    template <size_t i>
+    using at = typename std::tuple_element_t<i, std::tuple<T...>>;
+};
+
+// |callable_traits| captures elements of interest from function-like types (functions, function
+// pointers, and functors, including lambdas). Due to common usage patterns, const and non-const
+// functors are treated identically.
+//
+// Member types:
+//  |args|        - a |parameter_pack| that captures the parameter types of the function. See
+//                  |parameter_pack| for usage and details.
+//  |return_type| - the return type of the function.
+//  |type|        - the underlying functor or function pointer type. This member is absent if
+//                  |callable_traits| are requested for a raw function signature (as opposed to a
+//                  function pointer or functor; e.g. |callable_traits<void()>|).
+//  |signature|   - the type of the equivalent function.
+
+template <typename T>
+struct callable_traits : public callable_traits<decltype(&T::operator())> {};
+
+// Treat mutable call operators the same as const call operators.
+//
+// It would be equivalent to erase the const instead, but the common case is lambdas, which are
+// const, so prefer to nest less deeply for the common const case.
+template <typename FunctorType, typename ReturnType, typename... ArgTypes>
+struct callable_traits<ReturnType (FunctorType::*)(ArgTypes...)>
+    : public callable_traits<ReturnType (FunctorType::*)(ArgTypes...) const> {};
+
+// Common functor specialization.
+template <typename FunctorType, typename ReturnType, typename... ArgTypes>
+struct callable_traits<ReturnType (FunctorType::*)(ArgTypes...) const>
+    : public callable_traits<ReturnType (*)(ArgTypes...)> {
+
+    using type = FunctorType;
+};
+
+// Function pointer specialization.
+template <typename ReturnType, typename... ArgTypes>
+struct callable_traits<ReturnType (*)(ArgTypes...)>
+    : public callable_traits<ReturnType(ArgTypes...)> {
+
+    using type = ReturnType (*)(ArgTypes...);
+};
+
+// Base specialization.
+template <typename ReturnType, typename... ArgTypes>
+struct callable_traits<ReturnType(ArgTypes...)> {
+    using signature = ReturnType(ArgTypes...);
+    using return_type = ReturnType;
+    using args = parameter_pack<ArgTypes...>;
+
+    callable_traits() = delete;
+};
+
+// Determines whether a type has an operator() that can be invoked.
+template <typename T, typename = void_t<>>
+struct is_callable : public std::false_type {};
+template <typename ReturnType, typename... ArgTypes>
+struct is_callable<ReturnType (*)(ArgTypes...)>
+    : public std::true_type {};
+template <typename FunctorType, typename ReturnType, typename... ArgTypes>
+struct is_callable<ReturnType (FunctorType::*)(ArgTypes...)>
+    : public std::true_type {};
+template <typename T>
+struct is_callable<T, void_t<decltype(&T::operator())>>
+    : public std::true_type {};
+
+} // namespace fit
+
+#endif // LIB_FIT_TRAITS_H_
diff --git a/pkg/fit/include/lib/fit/variant.h b/pkg/fit/include/lib/fit/variant.h
new file mode 100644
index 0000000..f91a4a2
--- /dev/null
+++ b/pkg/fit/include/lib/fit/variant.h
@@ -0,0 +1,404 @@
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef LIB_FIT_VARIANT_H_
+#define LIB_FIT_VARIANT_H_
+
+#include <assert.h>
+
+#include <new>
+#include <type_traits>
+#include <utility>
+
+namespace fit {
+namespace internal {
+
+// This is a very basic partial implementation of |std::variant| which
+// is compatible with C++ 14.  In its current state, it only implements
+// enough of the API for internal usage.  Transforming this into a more
+// complete and precise implementation of |std::variant| is left as an
+// exercise for the reader.  ;)
+//
+// Some key differences:
+// - always requires first type to be monostate
+// - always default constructible
+// - no relational operators
+// - no visitors
+// - no find by type, only find by index
+// - no exception support
+// - simplified get/set methods
+
+// Unit type.
+struct monostate final {
+    constexpr bool operator==(const monostate& other) const { return true; }
+    constexpr bool operator!=(const monostate& other) const { return false; }
+};
+
+// Tag for requesting in-place initialization of a variant alternative by index.
+template <size_t index>
+struct in_place_index_t final {};
+
+#ifdef __cpp_inline_variables
+
+// Inline variables are only available on C++ 17 and beyond.
+template <size_t index>
+inline constexpr in_place_index_t<index> in_place_index{};
+
+#else
+
+// On C++ 14 we need to provide storage for the variable so we define
+// |in_place_index| as a reference instead.
+template <size_t index>
+struct in_place_index_holder {
+    static constexpr in_place_index_t<index> instance{};
+};
+
+template <size_t index>
+constexpr in_place_index_t<index> in_place_index_holder<index>::instance;
+
+template <size_t index>
+static constexpr const in_place_index_t<index>& in_place_index =
+    in_place_index_holder<index>::instance;
+
+#endif // __cpp_inline_variables
+
+// Stores the contents of the variant as a recursively nested union
+// of alternatives.  Conceptually it might be simpler to use
+// std::in_place_storage<> but we would lose the ability to treat the
+// storage as a literal type.
+template <typename... Ts>
+union variant_storage final {
+    static constexpr bool copy_construct_supported = true;
+    static constexpr bool move_construct_supported = true;
+
+    void copy_construct_from(size_t index, const variant_storage& other) {}
+    void move_construct_from(size_t index, variant_storage&& other) {}
+    void destroy(size_t index) {}
+    void swap(size_t index, variant_storage& other) {}
+};
+
+template <typename T0, typename... Ts>
+union variant_storage<T0, Ts...> final {
+    static constexpr bool copy_construct_supported =
+        std::is_copy_constructible<T0>::value &&
+        variant_storage<Ts...>::copy_construct_supported;
+    static constexpr bool move_construct_supported =
+        std::is_move_constructible<T0>::value &&
+        variant_storage<Ts...>::move_construct_supported;
+
+    constexpr variant_storage() = default;
+
+    template <typename... Args>
+    explicit constexpr variant_storage(in_place_index_t<0>, Args&&... args)
+        : alt(std::forward<Args>(args)...) {}
+
+    template <size_t index, typename... Args>
+    explicit constexpr variant_storage(in_place_index_t<index>, Args&&... args)
+        : rest(in_place_index<index - 1>, std::forward<Args>(args)...) {}
+
+    constexpr T0& get(in_place_index_t<0>) { return alt; }
+
+    constexpr const T0& get(in_place_index_t<0>) const { return alt; }
+
+    template <size_t index>
+    constexpr auto& get(in_place_index_t<index>) {
+        return rest.get(in_place_index<index - 1>);
+    }
+
+    template <size_t index>
+    constexpr const auto& get(in_place_index_t<index>) const {
+        return rest.get(in_place_index<index - 1>);
+    }
+
+    template <typename... Args>
+    auto& emplace(in_place_index_t<0>, Args&&... args) {
+        new (&alt) T0(std::forward<Args>(args)...);
+        return alt;
+    }
+
+    template <size_t index, typename... Args>
+    auto& emplace(in_place_index_t<index>, Args&&... args) {
+        return rest.emplace(in_place_index<index - 1>,
+                            std::forward<Args>(args)...);
+    }
+
+    void copy_construct_from(size_t index, const variant_storage& other) {
+        if (index == 0) {
+            new (&alt) T0(other.alt);
+        } else {
+            rest.copy_construct_from(index - 1, other.rest);
+        }
+    }
+
+    void move_construct_from(size_t index, variant_storage&& other) {
+        if (index == 0) {
+            new (&alt) T0(std::move(other.alt));
+        } else {
+            rest.move_construct_from(index - 1, std::move(other.rest));
+        }
+    }
+
+    void destroy(size_t index) {
+        if (index == 0) {
+            alt.~T0();
+        } else {
+            rest.destroy(index - 1);
+        }
+    }
+
+    void swap(size_t index, variant_storage& other) {
+        using std::swap;
+        if (index == 0) {
+            swap(alt, other.alt);
+        } else {
+            rest.swap(index - 1, other.rest);
+        }
+    }
+
+    T0 alt;
+    variant_storage<Ts...> rest;
+};
+
+// Holds the index and storage for a variant with a trivial destructor.
+template <typename... Ts>
+class variant_base_impl_trivial;
+template <typename... Ts>
+class variant_base_impl_trivial<monostate, Ts...> {
+public:
+    constexpr variant_base_impl_trivial()
+        : index_(0),
+          storage_(in_place_index<0>, monostate{}) {}
+
+    template <size_t index, typename... Args>
+    explicit constexpr variant_base_impl_trivial(
+        in_place_index_t<index>, Args&&... args)
+        : index_(index),
+          storage_(in_place_index<index>, std::forward<Args>(args)...) {}
+
+    // Used by emplace.
+    void destroy() {}
+
+protected:
+    size_t index_;
+    variant_storage<monostate, Ts...> storage_;
+};
+
+// Holds the index and storage for a variant with a non-trivial destructor.
+template <typename... Ts>
+class variant_base_impl_non_trivial;
+template <typename... Ts>
+class variant_base_impl_non_trivial<monostate, Ts...> {
+public:
+    constexpr variant_base_impl_non_trivial()
+        : index_(0),
+          storage_(in_place_index<0>, monostate{}) {}
+
+    template <size_t index, typename... Args>
+    explicit constexpr variant_base_impl_non_trivial(
+        in_place_index_t<index>, Args&&... args)
+        : index_(index),
+          storage_(in_place_index<index>, std::forward<Args>(args)...) {}
+
+    ~variant_base_impl_non_trivial() {
+        destroy();
+    }
+
+    // Used by emplace and by the destructor.
+    void destroy() {
+        storage_.destroy(index_);
+    }
+
+protected:
+    size_t index_;
+    union {
+        variant_storage<monostate, Ts...> storage_;
+    };
+};
+
+// Selects an appropriate variant base class depending on whether
+// its destructor is trivial or non-trivial.
+template <typename... Ts>
+using variant_base_impl =
+    std::conditional_t<
+        std::is_destructible<
+            variant_base_impl_trivial<Ts...>>::value,
+        variant_base_impl_trivial<Ts...>,
+        variant_base_impl_non_trivial<Ts...>>;
+
+// Implements non-trivial move-construction and move-assignment.
+template <typename... Ts>
+class variant_move_impl_non_trivial : protected variant_base_impl<Ts...> {
+    using base = variant_base_impl<Ts...>;
+
+public:
+    using base::base;
+
+    variant_move_impl_non_trivial(
+        const variant_move_impl_non_trivial& other) = default;
+
+    variant_move_impl_non_trivial(
+        variant_move_impl_non_trivial&& other) {
+        index_ = other.index_;
+        storage_.move_construct_from(index_, std::move(other.storage_));
+    }
+
+    variant_move_impl_non_trivial& operator=(
+        const variant_move_impl_non_trivial& other) = default;
+
+    variant_move_impl_non_trivial& operator=(
+        variant_move_impl_non_trivial&& other) {
+        if (&other == this)
+            return *this;
+        storage_.destroy(index_);
+        index_ = other.index_;
+        storage_.move_construct_from(index_, std::move(other.storage_));
+        return *this;
+    }
+
+protected:
+    using base::index_;
+    using base::storage_;
+};
+
+// Selects an appropriate variant base class for moving.
+template <typename... Ts>
+using variant_move_impl =
+    std::conditional_t<
+        (std::is_move_constructible<variant_base_impl<Ts...>>::value &&
+         std::is_move_assignable<variant_base_impl<Ts...>>::value) ||
+            !variant_storage<Ts...>::move_construct_supported,
+        variant_base_impl<Ts...>,
+        variant_move_impl_non_trivial<Ts...>>;
+
+// Implements non-trivial copy-construction and copy-assignment.
+template <typename... Ts>
+class variant_copy_impl_non_trivial : protected variant_move_impl<Ts...> {
+    using base = variant_move_impl<Ts...>;
+
+public:
+    using base::base;
+
+    variant_copy_impl_non_trivial(
+        const variant_copy_impl_non_trivial& other) {
+        index_ = other.index_;
+        storage_.copy_construct_from(index_, other.storage_);
+    }
+
+    variant_copy_impl_non_trivial(
+        variant_copy_impl_non_trivial&&) = default;
+
+    variant_copy_impl_non_trivial& operator=(
+        const variant_copy_impl_non_trivial& other) {
+        if (&other == this)
+            return *this;
+        storage_.destroy(index_);
+        index_ = other.index_;
+        storage_.copy_construct_from(index_, other.storage_);
+        return *this;
+    }
+
+    variant_copy_impl_non_trivial& operator=(
+        variant_copy_impl_non_trivial&&) = default;
+
+protected:
+    using base::index_;
+    using base::storage_;
+};
+
+// Selects an appropriate variant base class for copying.
+// Use the base impl if the type is trivially
+template <typename... Ts>
+using variant_copy_impl =
+    std::conditional_t<
+        (std::is_copy_constructible<variant_move_impl<Ts...>>::value &&
+         std::is_copy_assignable<variant_move_impl<Ts...>>::value) ||
+            !variant_storage<Ts...>::copy_construct_supported,
+        variant_move_impl<Ts...>,
+        variant_copy_impl_non_trivial<Ts...>>;
+
+// Actual variant type.
+template <typename... Ts>
+class variant : private variant_copy_impl<Ts...> {
+    using base = variant_copy_impl<Ts...>;
+
+public:
+    constexpr variant() = default;
+
+    template <size_t index, typename... Args>
+    explicit constexpr variant(in_place_index_t<index> i, Args&&... args)
+        : base(i, std::forward<Args>(args)...) {}
+
+    variant(const variant&) = default;
+    variant(variant&&) = default;
+    ~variant() = default;
+
+    variant& operator=(const variant&) = default;
+    variant& operator=(variant&&) = default;
+
+    constexpr size_t index() const { return index_; }
+
+    template <size_t index>
+    constexpr auto& get() {
+        assert(index_ == index);
+        return storage_.get(in_place_index<index>);
+    }
+
+    template <size_t index>
+    constexpr const auto& get() const {
+        assert(index_ == index);
+        return storage_.get(in_place_index<index>);
+    }
+
+    template <size_t index, typename... Args>
+    auto& emplace(Args&&... args) {
+        this->destroy();
+        index_ = index;
+        return storage_.emplace(in_place_index<index>,
+                                std::forward<Args>(args)...);
+    }
+
+    void swap(variant& other) {
+        using std::swap;
+        if (&other == this)
+            return;
+        if (index_ == other.index_) {
+            storage_.swap(index_, other.storage_);
+        } else {
+            variant temp(std::move(*this));
+            *this = std::move(other);
+            other = std::move(temp);
+        }
+    }
+
+private:
+    using base::index_;
+    using base::storage_;
+};
+
+// Swaps variants.
+template <typename... Ts>
+void swap(variant<Ts...>& a, variant<Ts...>& b) {
+    a.swap(b);
+}
+
+// Gets the type of a variant alternative with the given index.
+template <size_t index, typename Variant>
+struct variant_alternative;
+
+template <size_t index, typename T0, typename... Ts>
+struct variant_alternative<index, variant<T0, Ts...>>
+    : variant_alternative<index - 1, variant<Ts...>> {};
+
+template <typename T0, typename... Ts>
+struct variant_alternative<0, variant<T0, Ts...>> {
+    using type = T0;
+};
+
+template <size_t index, typename Variant>
+using variant_alternative_t = typename variant_alternative<index, Variant>::type;
+
+} // namespace internal
+} // namespace fit
+
+#endif // LIB_FIT_VARIANT_H_
diff --git a/pkg/fit/meta.json b/pkg/fit/meta.json
new file mode 100644
index 0000000..db86eb9
--- /dev/null
+++ b/pkg/fit/meta.json
@@ -0,0 +1,57 @@
+{
+  "banjo_deps": [], 
+  "deps": [], 
+  "fidl_deps": [], 
+  "files": [
+    "pkg/fit/promise.cpp", 
+    "pkg/fit/scheduler.cpp", 
+    "pkg/fit/sequencer.cpp", 
+    "pkg/fit/single_threaded_executor.cpp", 
+    "pkg/fit/include/lib/fit/bridge.h", 
+    "pkg/fit/include/lib/fit/bridge_internal.h", 
+    "pkg/fit/include/lib/fit/defer.h", 
+    "pkg/fit/include/lib/fit/function.h", 
+    "pkg/fit/include/lib/fit/function_internal.h", 
+    "pkg/fit/include/lib/fit/function_traits.h", 
+    "pkg/fit/include/lib/fit/nullable.h", 
+    "pkg/fit/include/lib/fit/optional.h", 
+    "pkg/fit/include/lib/fit/promise.h", 
+    "pkg/fit/include/lib/fit/promise_internal.h", 
+    "pkg/fit/include/lib/fit/result.h", 
+    "pkg/fit/include/lib/fit/scheduler.h", 
+    "pkg/fit/include/lib/fit/sequencer.h", 
+    "pkg/fit/include/lib/fit/single_threaded_executor.h", 
+    "pkg/fit/include/lib/fit/thread_safety.h", 
+    "pkg/fit/include/lib/fit/traits.h", 
+    "pkg/fit/include/lib/fit/variant.h"
+  ], 
+  "headers": [
+    "pkg/fit/include/lib/fit/bridge.h", 
+    "pkg/fit/include/lib/fit/bridge_internal.h", 
+    "pkg/fit/include/lib/fit/defer.h", 
+    "pkg/fit/include/lib/fit/function.h", 
+    "pkg/fit/include/lib/fit/function_internal.h", 
+    "pkg/fit/include/lib/fit/function_traits.h", 
+    "pkg/fit/include/lib/fit/nullable.h", 
+    "pkg/fit/include/lib/fit/optional.h", 
+    "pkg/fit/include/lib/fit/promise.h", 
+    "pkg/fit/include/lib/fit/promise_internal.h", 
+    "pkg/fit/include/lib/fit/result.h", 
+    "pkg/fit/include/lib/fit/scheduler.h", 
+    "pkg/fit/include/lib/fit/sequencer.h", 
+    "pkg/fit/include/lib/fit/single_threaded_executor.h", 
+    "pkg/fit/include/lib/fit/thread_safety.h", 
+    "pkg/fit/include/lib/fit/traits.h", 
+    "pkg/fit/include/lib/fit/variant.h"
+  ], 
+  "include_dir": "pkg/fit/include", 
+  "name": "fit", 
+  "root": "pkg/fit", 
+  "sources": [
+    "pkg/fit/promise.cpp", 
+    "pkg/fit/scheduler.cpp", 
+    "pkg/fit/sequencer.cpp", 
+    "pkg/fit/single_threaded_executor.cpp"
+  ], 
+  "type": "cc_source_library"
+}
\ No newline at end of file
diff --git a/pkg/fit/promise.cpp b/pkg/fit/promise.cpp
new file mode 100644
index 0000000..8309f00
--- /dev/null
+++ b/pkg/fit/promise.cpp
@@ -0,0 +1,57 @@
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Can't compile this for Zircon userspace yet since libstdc++ isn't available.
+#ifndef FIT_NO_STD_FOR_ZIRCON_USERSPACE
+
+#include <lib/fit/promise.h>
+
+namespace fit {
+
+suspended_task::suspended_task(const suspended_task& other)
+    : resolver_(other.resolver_),
+      ticket_(resolver_ ? resolver_->duplicate_ticket(other.ticket_) : 0) {}
+
+suspended_task::suspended_task(suspended_task&& other)
+    : resolver_(other.resolver_), ticket_(other.ticket_) {
+    other.resolver_ = nullptr;
+}
+
+suspended_task::~suspended_task() {
+    reset();
+}
+
+void suspended_task::resolve(bool resume_task) {
+    if (resolver_) {
+        // Move the ticket to the stack to guard against possible re-entrance
+        // occurring as a side-effect of the task's own destructor running.
+        resolver* cached_resolver = resolver_;
+        ticket cached_ticket = ticket_;
+        resolver_ = nullptr;
+        cached_resolver->resolve_ticket(cached_ticket, resume_task);
+    }
+}
+
+suspended_task& suspended_task::operator=(const suspended_task& other) {
+    if (this != &other) {
+        reset();
+        resolver_ = other.resolver_;
+        ticket_ = resolver_ ? resolver_->duplicate_ticket(other.ticket_) : 0;
+    }
+    return *this;
+}
+
+suspended_task& suspended_task::operator=(suspended_task&& other) {
+    if (this != &other) {
+        reset();
+        resolver_ = other.resolver_;
+        ticket_ = other.ticket_;
+        other.resolver_ = nullptr;
+    }
+    return *this;
+}
+
+} // namespace fit
+
+#endif // FIT_NO_STD_FOR_ZIRCON_USERSPACE
diff --git a/pkg/fit/scheduler.cpp b/pkg/fit/scheduler.cpp
new file mode 100644
index 0000000..69acc03
--- /dev/null
+++ b/pkg/fit/scheduler.cpp
@@ -0,0 +1,128 @@
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Can't compile this for Zircon userspace yet since libstdc++ isn't available.
+#ifndef FIT_NO_STD_FOR_ZIRCON_USERSPACE
+
+#include <lib/fit/scheduler.h>
+
+#include <map>
+#include <queue>
+#include <utility>
+
+namespace fit {
+namespace subtle {
+
+scheduler::scheduler() = default;
+
+scheduler::~scheduler() = default;
+
+void scheduler::schedule_task(pending_task task) {
+    assert(task);
+    runnable_tasks_.push(std::move(task));
+}
+
+suspended_task::ticket scheduler::obtain_ticket(uint32_t initial_refs) {
+    suspended_task::ticket ticket = next_ticket_++;
+    tickets_.emplace(ticket, ticket_record(initial_refs));
+    return ticket;
+}
+
+void scheduler::finalize_ticket(suspended_task::ticket ticket,
+                                pending_task* task) {
+    auto it = tickets_.find(ticket);
+    assert(it != tickets_.end());
+    assert(!it->second.task);
+    assert(it->second.ref_count > 0);
+    assert(task);
+
+    it->second.ref_count--;
+    if (!*task) {
+        // task already finished
+    } else if (it->second.was_resumed) {
+        // task immediately became runnable
+        runnable_tasks_.push(std::move(*task));
+    } else if (it->second.ref_count > 0) {
+        // task remains suspended
+        it->second.task = std::move(*task);
+        suspended_task_count_++;
+    } // else, task was abandoned and caller retains ownership of it
+    if (it->second.ref_count == 0) {
+        tickets_.erase(it);
+    }
+}
+
+void scheduler::duplicate_ticket(suspended_task::ticket ticket) {
+    auto it = tickets_.find(ticket);
+    assert(it != tickets_.end());
+    assert(it->second.ref_count > 0);
+
+    it->second.ref_count++;
+    assert(it->second.ref_count != 0); // did we really make 4 billion refs?!
+}
+
+pending_task scheduler::release_ticket(suspended_task::ticket ticket) {
+    auto it = tickets_.find(ticket);
+    assert(it != tickets_.end());
+    assert(it->second.ref_count > 0);
+
+    it->second.ref_count--;
+    if (it->second.ref_count == 0) {
+        pending_task task = std::move(it->second.task);
+        if (task) {
+            assert(suspended_task_count_ > 0);
+            suspended_task_count_--;
+        }
+        tickets_.erase(it);
+        return task;
+    }
+    return pending_task();
+}
+
+bool scheduler::resume_task_with_ticket(suspended_task::ticket ticket) {
+    auto it = tickets_.find(ticket);
+    assert(it != tickets_.end());
+    assert(it->second.ref_count > 0);
+
+    bool did_resume = false;
+    it->second.ref_count--;
+    if (!it->second.was_resumed) {
+        it->second.was_resumed = true;
+        if (it->second.task) {
+            did_resume = true;
+            assert(suspended_task_count_ > 0);
+            suspended_task_count_--;
+            runnable_tasks_.push(std::move(it->second.task));
+        }
+    }
+    if (it->second.ref_count == 0) {
+        tickets_.erase(it);
+    }
+    return did_resume;
+}
+
+void scheduler::take_runnable_tasks(task_queue* tasks) {
+    assert(tasks && tasks->empty());
+    runnable_tasks_.swap(*tasks);
+}
+
+void scheduler::take_all_tasks(task_queue* tasks) {
+    assert(tasks && tasks->empty());
+
+    runnable_tasks_.swap(*tasks);
+    if (suspended_task_count_ > 0) {
+        for (auto& item : tickets_) {
+            if (item.second.task) {
+                assert(suspended_task_count_ > 0);
+                suspended_task_count_--;
+                tasks->push(std::move(item.second.task));
+            }
+        }
+    }
+}
+
+} // namespace subtle
+} // namespace fit
+
+#endif // FIT_NO_STD_FOR_ZIRCON_USERSPACE
diff --git a/pkg/fit/sequencer.cpp b/pkg/fit/sequencer.cpp
new file mode 100644
index 0000000..687db67
--- /dev/null
+++ b/pkg/fit/sequencer.cpp
@@ -0,0 +1,31 @@
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Can't compile this for Zircon userspace yet since libstdc++ isn't available.
+#ifndef FIT_NO_STD_FOR_ZIRCON_USERSPACE
+
+#include <lib/fit/sequencer.h>
+
+namespace fit {
+
+sequencer::sequencer() {
+    // Capture a new consumer and intentionally abandon its associated
+    // completer so that a promise chained onto the consumer using
+    // |promise_or()| will become immediately runnable.
+    fit::bridge<> bridge;
+    prior_ = std::move(bridge.consumer());
+}
+
+sequencer::~sequencer() = default;
+
+fit::consumer<> sequencer::swap_prior(fit::consumer<> new_prior) {
+    std::lock_guard<std::mutex> lock(mutex_);
+    fit::consumer<> old_prior = std::move(prior_);
+    prior_ = std::move(new_prior);
+    return old_prior;
+}
+
+} // namespace fit
+
+#endif // FIT_NO_STD_FOR_ZIRCON_USERSPACE
diff --git a/pkg/fit/single_threaded_executor.cpp b/pkg/fit/single_threaded_executor.cpp
new file mode 100644
index 0000000..ba738d0
--- /dev/null
+++ b/pkg/fit/single_threaded_executor.cpp
@@ -0,0 +1,240 @@
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Can't compile this for Zircon userspace yet since libstdc++ isn't available.
+#ifndef FIT_NO_STD_FOR_ZIRCON_USERSPACE
+
+#include <condition_variable>
+#include <mutex>
+
+#include <lib/fit/single_threaded_executor.h>
+#include <lib/fit/thread_safety.h>
+
+namespace fit {
+
+// The dispatcher runs tasks and provides the suspended task resolver.
+//
+// The lifetime of this object is somewhat complex since there are pointers
+// to it from multiple sources which are released in different ways.
+//
+// - |single_threaded_executor| holds a pointer in |dispatcher_| which it releases
+//   after calling |shutdown()| to inform the dispatcher of its own demise
+// - |suspended_task| holds a pointer to the dispatcher's resolver
+//   interface and the number of outstanding pointers corresponds to the
+//   number of outstanding suspended task tickets tracked by |scheduler_|.
+//
+// The dispatcher deletes itself once all pointers have been released.
+class single_threaded_executor::dispatcher_impl final
+    : public suspended_task::resolver {
+public:
+    dispatcher_impl();
+
+    void shutdown();
+    void schedule_task(pending_task task);
+    void run(context_impl& context);
+    suspended_task suspend_current_task();
+
+    suspended_task::ticket duplicate_ticket(
+        suspended_task::ticket ticket) override;
+    void resolve_ticket(
+        suspended_task::ticket ticket, bool resume_task) override;
+
+private:
+    ~dispatcher_impl() override;
+
+    void wait_for_runnable_tasks(
+        fit::subtle::scheduler::task_queue* out_tasks);
+    void run_task(pending_task* task, context& context);
+
+    suspended_task::ticket current_task_ticket_ = 0;
+    std::condition_variable wake_;
+
+    // A bunch of state that is guarded by a mutex.
+    struct {
+        std::mutex mutex_;
+        bool was_shutdown_ FIT_GUARDED(mutex_) = false;
+        bool need_wake_ FIT_GUARDED(mutex_) = false;
+        fit::subtle::scheduler scheduler_ FIT_GUARDED(mutex_);
+    } guarded_;
+};
+
+single_threaded_executor::single_threaded_executor()
+    : context_(this), dispatcher_(new dispatcher_impl()) {}
+
+single_threaded_executor::~single_threaded_executor() {
+    dispatcher_->shutdown();
+}
+
+void single_threaded_executor::schedule_task(pending_task task) {
+    assert(task);
+    dispatcher_->schedule_task(std::move(task));
+}
+
+void single_threaded_executor::run() {
+    dispatcher_->run(context_);
+}
+
+single_threaded_executor::context_impl::context_impl(single_threaded_executor* executor)
+    : executor_(executor) {}
+
+single_threaded_executor::context_impl::~context_impl() = default;
+
+single_threaded_executor* single_threaded_executor::context_impl::executor() const {
+    return executor_;
+}
+
+suspended_task single_threaded_executor::context_impl::suspend_task() {
+    return executor_->dispatcher_->suspend_current_task();
+}
+
+single_threaded_executor::dispatcher_impl::dispatcher_impl() = default;
+
+single_threaded_executor::dispatcher_impl::~dispatcher_impl() {
+    std::lock_guard<std::mutex> lock(guarded_.mutex_);
+    assert(guarded_.was_shutdown_);
+    assert(!guarded_.scheduler_.has_runnable_tasks());
+    assert(!guarded_.scheduler_.has_suspended_tasks());
+    assert(!guarded_.scheduler_.has_outstanding_tickets());
+}
+
+void single_threaded_executor::dispatcher_impl::shutdown() {
+    fit::subtle::scheduler::task_queue tasks; // drop outside of the lock
+    {
+        std::lock_guard<std::mutex> lock(guarded_.mutex_);
+        assert(!guarded_.was_shutdown_);
+        guarded_.was_shutdown_ = true;
+        guarded_.scheduler_.take_all_tasks(&tasks);
+        if (guarded_.scheduler_.has_outstanding_tickets()) {
+            return; // can't delete self yet
+        }
+    }
+
+    // Must destroy self outside of the lock.
+    delete this;
+}
+
+void single_threaded_executor::dispatcher_impl::schedule_task(pending_task task) {
+    {
+        std::lock_guard<std::mutex> lock(guarded_.mutex_);
+        assert(!guarded_.was_shutdown_);
+        guarded_.scheduler_.schedule_task(std::move(task));
+        if (!guarded_.need_wake_) {
+            return; // don't need to wake
+        }
+        guarded_.need_wake_ = false;
+    }
+
+    // It is more efficient to notify outside the lock.
+    wake_.notify_one();
+}
+
+void single_threaded_executor::dispatcher_impl::run(context_impl& context) {
+    fit::subtle::scheduler::task_queue tasks;
+    for (;;) {
+        wait_for_runnable_tasks(&tasks);
+        if (tasks.empty()) {
+            return; // all done!
+        }
+
+        do {
+            run_task(&tasks.front(), context);
+            tasks.pop(); // the task may be destroyed here if it was not suspended
+        } while (!tasks.empty());
+    }
+}
+
+// Must only be called while |run_task()| is running a task.
+// This happens when the task's continuation calls |context::suspend_task()|
+// upon the context it received as an argument.
+suspended_task single_threaded_executor::dispatcher_impl::suspend_current_task() {
+    std::lock_guard<std::mutex> lock(guarded_.mutex_);
+    assert(!guarded_.was_shutdown_);
+    if (current_task_ticket_ == 0) {
+        current_task_ticket_ = guarded_.scheduler_.obtain_ticket(
+            2 /*initial_refs*/);
+    } else {
+        guarded_.scheduler_.duplicate_ticket(current_task_ticket_);
+    }
+    return suspended_task(this, current_task_ticket_);
+}
+
+// Unfortunately std::unique_lock does not support thread-safety annotations
+void single_threaded_executor::dispatcher_impl::wait_for_runnable_tasks(
+    fit::subtle::scheduler::task_queue* out_tasks) FIT_NO_THREAD_SAFETY_ANALYSIS {
+    std::unique_lock<std::mutex> lock(guarded_.mutex_);
+    for (;;) {
+        assert(!guarded_.was_shutdown_);
+        guarded_.scheduler_.take_runnable_tasks(out_tasks);
+        if (!out_tasks->empty()) {
+            return; // got some tasks
+        }
+        if (!guarded_.scheduler_.has_suspended_tasks()) {
+            return; // all done!
+        }
+        guarded_.need_wake_ = true;
+        wake_.wait(lock);
+        guarded_.need_wake_ = false;
+    }
+}
+
+void single_threaded_executor::dispatcher_impl::run_task(pending_task* task,
+                                                         context& context) {
+    assert(current_task_ticket_ == 0);
+    const bool finished = (*task)(context);
+    assert(!*task == finished);
+    (void)finished;
+    if (current_task_ticket_ == 0) {
+        return; // task was not suspended, no ticket was produced
+    }
+
+    std::lock_guard<std::mutex> lock(guarded_.mutex_);
+    assert(!guarded_.was_shutdown_);
+    guarded_.scheduler_.finalize_ticket(current_task_ticket_, task);
+    current_task_ticket_ = 0;
+}
+
+suspended_task::ticket single_threaded_executor::dispatcher_impl::duplicate_ticket(
+    suspended_task::ticket ticket) {
+    std::lock_guard<std::mutex> lock(guarded_.mutex_);
+    guarded_.scheduler_.duplicate_ticket(ticket);
+    return ticket;
+}
+
+void single_threaded_executor::dispatcher_impl::resolve_ticket(
+    suspended_task::ticket ticket, bool resume_task) {
+    pending_task abandoned_task; // drop outside of the lock
+    bool do_wake = false;
+    {
+        std::lock_guard<std::mutex> lock(guarded_.mutex_);
+        if (resume_task) {
+            guarded_.scheduler_.resume_task_with_ticket(ticket);
+        } else {
+            abandoned_task = guarded_.scheduler_.release_ticket(ticket);
+        }
+        if (guarded_.was_shutdown_) {
+            assert(!guarded_.need_wake_);
+            if (guarded_.scheduler_.has_outstanding_tickets()) {
+                return; // can't shutdown yet
+            }
+        } else if (guarded_.need_wake_ &&
+                   (guarded_.scheduler_.has_runnable_tasks() ||
+                    !guarded_.scheduler_.has_suspended_tasks())) {
+            guarded_.need_wake_ = false;
+            do_wake = true;
+        } else {
+            return; // nothing else to do
+        }
+    }
+
+    // Must do this outside of the lock.
+    if (do_wake) {
+        wake_.notify_one();
+    } else {
+        delete this;
+    }
+}
+
+} // namespace fit
+
+#endif // FIT_NO_STD_FOR_ZIRCON_USERSPACE
diff --git a/pkg/images_cpp/images.cc b/pkg/images_cpp/images.cc
new file mode 100644
index 0000000..17803c6
--- /dev/null
+++ b/pkg/images_cpp/images.cc
@@ -0,0 +1,84 @@
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "lib/images/cpp/images.h"
+
+#include <zircon/assert.h>
+
+namespace images {
+
+// Overall bits per pixel, across all pixel data in the whole image.
+size_t BitsPerPixel(const fuchsia::images::PixelFormat& pixel_format) {
+  switch (pixel_format) {
+    case fuchsia::images::PixelFormat::BGRA_8:
+      return 4u * 8u;
+    case fuchsia::images::PixelFormat::YUY2:
+      return 2u * 8u;
+    case fuchsia::images::PixelFormat::NV12:
+      return 12;
+    case fuchsia::images::PixelFormat::YV12:
+      return 12;
+  }
+  ZX_PANIC("Unknown Pixel Format: %d", static_cast<int>(pixel_format));
+  return 0;
+}
+
+size_t StrideBytesPerWidthPixel(
+    const fuchsia::images::PixelFormat& pixel_format) {
+  switch (pixel_format) {
+    case fuchsia::images::PixelFormat::BGRA_8:
+      return 4u;
+    case fuchsia::images::PixelFormat::YUY2:
+      return 2u;
+    case fuchsia::images::PixelFormat::NV12:
+      return 1u;
+    case fuchsia::images::PixelFormat::YV12:
+      return 1u;
+  }
+  ZX_PANIC("Unknown Pixel Format: %d", static_cast<int>(pixel_format));
+  return 0;
+}
+
+size_t MaxSampleAlignment(const fuchsia::images::PixelFormat& pixel_format) {
+  switch (pixel_format) {
+    case fuchsia::images::PixelFormat::BGRA_8:
+      return 4u;
+    case fuchsia::images::PixelFormat::YUY2:
+      return 2u;
+    case fuchsia::images::PixelFormat::NV12:
+      // In the sense that line stride "must preserve pixel alignment", which is
+      // what MaxSampleAlignment() is used for, NV12 ~~has (very roughly
+      // speaking) a pixel alignment of 2, ~~because the width of the Y plane in
+      // this implementation must be even, and ~because the interleaved UV data
+      // after the planar Y data is 2 bytes per sample, so we may as well
+      // require UV samples to remain aligned UV line to UV line.
+      return 2u;
+    case fuchsia::images::PixelFormat::YV12:
+      // In the sense that line stride "must preserve pixel alignment", which is
+      // what MaxSampleAlignment() is used for, YV12 ~~has (very roughly
+      // speaking) a pixel alignment of 2, ~~because the width of the Y plane in
+      // this implementation must be even.
+      return 2u;
+  }
+  ZX_PANIC("Unknown Pixel Format: %d", static_cast<int>(pixel_format));
+  return 0;
+}
+
+size_t ImageSize(const fuchsia::images::ImageInfo& image_info) {
+  ZX_DEBUG_ASSERT(image_info.tiling == fuchsia::images::Tiling::LINEAR);
+  switch (image_info.pixel_format) {
+    case fuchsia::images::PixelFormat::BGRA_8:
+    case fuchsia::images::PixelFormat::YUY2:
+      return image_info.height * image_info.stride;
+    case fuchsia::images::PixelFormat::NV12:
+      return image_info.height * image_info.stride * 3 / 2;
+    case fuchsia::images::PixelFormat::YV12:
+      return image_info.height * image_info.stride * 3 / 2;
+  }
+  ZX_PANIC("Unknown Pixel Format: %d",
+           static_cast<int>(image_info.pixel_format));
+  return 0;
+}
+
+}  // namespace images
diff --git a/pkg/images_cpp/include/lib/images/cpp/images.h b/pkg/images_cpp/include/lib/images/cpp/images.h
new file mode 100644
index 0000000..48d75e6
--- /dev/null
+++ b/pkg/images_cpp/include/lib/images/cpp/images.h
@@ -0,0 +1,41 @@
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef LIB_IMAGES_CPP_IMAGES_H_
+#define LIB_IMAGES_CPP_IMAGES_H_
+
+#include <fuchsia/images/cpp/fidl.h>
+
+#include <stdint.h>
+
+namespace images {
+
+// Returns the number of bits per pixel for the given format.  This is the bits
+// per pixel in the overall image across all bytes that contain pixel data.  For
+// example, NV12 is 12 bits per pixel.
+size_t BitsPerPixel(const fuchsia::images::PixelFormat& pixel_format);
+
+// This is the number of stride bytes per pixel of width.  For formats such as
+// NV12 that separate Y and UV data, this is the number of stride bytes of the Y
+// plane.  NV12 has the same stride for the UV data.  formats with a different
+// stride for UV data vs Y data are not handled yet.
+size_t StrideBytesPerWidthPixel(
+    const fuchsia::images::PixelFormat& pixel_format);
+
+// Returns the pixel alignment for the given format.
+//
+// This is technically something closer to "max sample alignment" for the given
+// format.  For example, NV12 returns 2 here because its UV interleaved data has
+// 2 bytes per sample, despite its Y plane having 1 byte per sample.
+//
+// The stride is required to be divisible by this alignment.
+size_t MaxSampleAlignment(const fuchsia::images::PixelFormat& pixel_format);
+
+// This would be height * stride, if it weren't for formats like NV12, where it
+// isn't.  The output is bytes.
+size_t ImageSize(const fuchsia::images::ImageInfo& image_info);
+
+}  // namespace images
+
+#endif  // LIB_IMAGES_CPP_IMAGES_H_
diff --git a/pkg/images_cpp/meta.json b/pkg/images_cpp/meta.json
new file mode 100644
index 0000000..61fdef4
--- /dev/null
+++ b/pkg/images_cpp/meta.json
@@ -0,0 +1,16 @@
+{
+  "deps": [], 
+  "fidl_deps": [
+    "fuchsia.images"
+  ], 
+  "headers": [
+    "pkg/images_cpp/include/lib/images/cpp/images.h"
+  ], 
+  "include_dir": "pkg/images_cpp/include", 
+  "name": "images_cpp", 
+  "root": "pkg/images_cpp", 
+  "sources": [
+    "pkg/images_cpp/images.cc"
+  ], 
+  "type": "cc_source_library"
+}
\ No newline at end of file
diff --git a/pkg/memfs/include/lib/memfs/memfs.h b/pkg/memfs/include/lib/memfs/memfs.h
new file mode 100644
index 0000000..7f49a96
--- /dev/null
+++ b/pkg/memfs/include/lib/memfs/memfs.h
@@ -0,0 +1,64 @@
+// Copyright 2017 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef LIB_MEMFS_INCLUDE_LIB_MEMFS_MEMFS_H_
+#define LIB_MEMFS_INCLUDE_LIB_MEMFS_MEMFS_H_
+
+#include <lib/async/dispatcher.h>
+#include <lib/sync/completion.h>
+#include <zircon/compiler.h>
+#include <zircon/types.h>
+
+__BEGIN_CDECLS
+
+typedef struct memfs_filesystem memfs_filesystem_t;
+
+// Given an async dispatcher, create an in-memory filesystem.
+//
+// Returns the MemFS filesystem object in |out_fs|. This object
+// must be freed by memfs_free_filesystem.
+//
+// Returns a handle to the root directory in |out_root|.
+__EXPORT zx_status_t memfs_create_filesystem(async_dispatcher_t* dispatcher,
+                                             memfs_filesystem_t** out_fs,
+                                             zx_handle_t* out_root);
+
+// Same as memfs_create_filesystem, but with an extra |max_num_pages| option.
+//
+// Specify the maximum number of pages available to the fs via |max_num_pages|.
+// This puts a bound on memory consumption.
+__EXPORT zx_status_t memfs_create_filesystem_with_page_limit(async_dispatcher_t* dispatcher,
+                                                             size_t max_num_pages,
+                                                             memfs_filesystem_t** out_fs,
+                                                             zx_handle_t* out_root);
+
+// Frees a MemFS filesystem, unmounting any sub-filesystems that
+// may exist.
+//
+// Requires that the async handler dispatcher provided to
+// |memfs_create_filesystem| still be running.
+//
+// Signals the optional argument |unmounted| when memfs has torn down.
+__EXPORT void memfs_free_filesystem(memfs_filesystem_t* fs, sync_completion_t* unmounted);
+
+// Creates an in-memory filesystem and installs it into the local namespace at
+// the given path.
+//
+// Operations on the filesystem are serviced by the given async dispatcher.
+//
+// Returns |ZX_ERR_ALREADY_EXISTS| if |path| already exists in the namespace for
+// this process.
+__EXPORT zx_status_t memfs_install_at(async_dispatcher_t* dispatcher, const char* path);
+
+// Same as memfs_install_at, but with an extra |max_num_pages| option.
+//
+// Specify the maximum number of pages available to the fs via |max_num_pages|.
+// This puts a bound on memory consumption.
+__EXPORT zx_status_t memfs_install_at_with_page_limit(async_dispatcher_t* dispatcher,
+                                                      size_t max_num_pages,
+                                                      const char* path);
+
+__END_CDECLS
+
+#endif // LIB_MEMFS_INCLUDE_LIB_MEMFS_MEMFS_H_
diff --git a/pkg/memfs/meta.json b/pkg/memfs/meta.json
new file mode 100644
index 0000000..1492c3e
--- /dev/null
+++ b/pkg/memfs/meta.json
@@ -0,0 +1,26 @@
+{
+  "binaries": {
+    "arm64": {
+      "debug": ".build-id/bf/c0f8386f84cd2c91ccae603bc6910bdbaf7f29.debug", 
+      "dist": "arch/arm64/dist/libmemfs.so", 
+      "link": "arch/arm64/lib/libmemfs.so"
+    }, 
+    "x64": {
+      "debug": ".build-id/7b/1c4f16beffe8102284ef4860a2a92696ed5045.debug", 
+      "dist": "arch/x64/dist/libmemfs.so", 
+      "link": "arch/x64/lib/libmemfs.so"
+    }
+  }, 
+  "deps": [
+    "fdio", 
+    "trace-engine"
+  ], 
+  "format": "shared", 
+  "headers": [
+    "pkg/memfs/include/lib/memfs/memfs.h"
+  ], 
+  "include_dir": "pkg/memfs/include", 
+  "name": "memfs", 
+  "root": "pkg/memfs", 
+  "type": "cc_prebuilt_library"
+}
\ No newline at end of file
diff --git a/pkg/scenic_cpp/commands.cc b/pkg/scenic_cpp/commands.cc
new file mode 100644
index 0000000..4991905
--- /dev/null
+++ b/pkg/scenic_cpp/commands.cc
@@ -0,0 +1,1300 @@
+// Copyright 2017 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "lib/ui/scenic/cpp/commands.h"
+
+#include <array>
+
+#include <zircon/assert.h>
+
+namespace scenic {
+
+fuchsia::ui::scenic::Command NewCommand(fuchsia::ui::gfx::Command command) {
+  fuchsia::ui::scenic::Command scenic_command;
+  scenic_command.set_gfx(std::move(command));
+  return scenic_command;
+}
+
+fuchsia::ui::scenic::Command NewCommand(fuchsia::ui::input::Command command) {
+  fuchsia::ui::scenic::Command scenic_command;
+  scenic_command.set_input(std::move(command));
+  return scenic_command;
+}
+
+// Helper function for all resource creation functions.
+fuchsia::ui::gfx::Command NewCreateResourceCmd(
+    uint32_t id, fuchsia::ui::gfx::ResourceArgs resource) {
+  fuchsia::ui::gfx::CreateResourceCmd create_resource;
+  create_resource.id = id;
+  create_resource.resource = std::move(resource);
+
+  fuchsia::ui::gfx::Command command;
+  command.set_create_resource(std::move(create_resource));
+
+  return command;
+}
+
+fuchsia::ui::gfx::Command NewCreateMemoryCmd(
+    uint32_t id, zx::vmo vmo, uint64_t allocation_size,
+    fuchsia::images::MemoryType memory_type) {
+  fuchsia::ui::gfx::MemoryArgs memory;
+  memory.vmo = std::move(vmo);
+  memory.allocation_size = allocation_size;
+  memory.memory_type = memory_type;
+
+  fuchsia::ui::gfx::ResourceArgs resource;
+  resource.set_memory(std::move(memory));
+
+  return NewCreateResourceCmd(id, std::move(resource));
+}
+
+fuchsia::ui::gfx::Command NewCreateImageCmd(uint32_t id, uint32_t memory_id,
+                                            uint32_t memory_offset,
+                                            fuchsia::images::ImageInfo info) {
+  fuchsia::ui::gfx::ImageArgs image;
+  image.memory_id = memory_id;
+  image.memory_offset = memory_offset;
+  image.info = std::move(info);
+
+  fuchsia::ui::gfx::ResourceArgs resource;
+  resource.set_image(std::move(image));
+
+  return NewCreateResourceCmd(id, std::move(resource));
+}
+
+fuchsia::ui::gfx::Command NewCreateImagePipeCmd(
+    uint32_t id, ::fidl::InterfaceRequest<fuchsia::images::ImagePipe> request) {
+  fuchsia::ui::gfx::ImagePipeArgs image_pipe;
+  image_pipe.image_pipe_request = std::move(request);
+
+  fuchsia::ui::gfx::ResourceArgs resource;
+  resource.set_image_pipe(std::move(image_pipe));
+  return NewCreateResourceCmd(id, std::move(resource));
+}
+
+fuchsia::ui::gfx::Command NewCreateImageCmd(
+    uint32_t id, uint32_t memory_id, uint32_t memory_offset,
+    fuchsia::images::PixelFormat format,
+    fuchsia::images::ColorSpace color_space, fuchsia::images::Tiling tiling,
+    uint32_t width, uint32_t height, uint32_t stride) {
+  fuchsia::images::ImageInfo info;
+  info.pixel_format = format;
+  info.color_space = color_space;
+  info.tiling = tiling;
+  info.width = width;
+  info.height = height;
+  info.stride = stride;
+  return NewCreateImageCmd(id, memory_id, memory_offset, std::move(info));
+}
+
+fuchsia::ui::gfx::Command NewCreateBufferCmd(uint32_t id, uint32_t memory_id,
+                                             uint32_t memory_offset,
+                                             uint32_t num_bytes) {
+  fuchsia::ui::gfx::BufferArgs buffer;
+  buffer.memory_id = memory_id;
+  buffer.memory_offset = memory_offset;
+  buffer.num_bytes = num_bytes;
+
+  fuchsia::ui::gfx::ResourceArgs resource;
+  resource.set_buffer(std::move(buffer));
+
+  return NewCreateResourceCmd(id, std::move(resource));
+}
+
+fuchsia::ui::gfx::Command NewCreateCompositorCmd(uint32_t id) {
+  fuchsia::ui::gfx::CompositorArgs compositor;
+
+  fuchsia::ui::gfx::ResourceArgs resource;
+  resource.set_compositor(std::move(compositor));
+
+  return NewCreateResourceCmd(id, std::move(resource));
+}
+
+fuchsia::ui::gfx::Command NewCreateDisplayCompositorCmd(uint32_t id) {
+  fuchsia::ui::gfx::DisplayCompositorArgs display_compositor;
+
+  fuchsia::ui::gfx::ResourceArgs resource;
+  resource.set_display_compositor(std::move(display_compositor));
+
+  return NewCreateResourceCmd(id, std::move(resource));
+}
+
+fuchsia::ui::gfx::Command NewCreateLayerStackCmd(uint32_t id) {
+  fuchsia::ui::gfx::LayerStackArgs layer_stack;
+
+  fuchsia::ui::gfx::ResourceArgs resource;
+  resource.set_layer_stack(std::move(layer_stack));
+
+  return NewCreateResourceCmd(id, std::move(resource));
+}
+
+fuchsia::ui::gfx::Command NewCreateLayerCmd(uint32_t id) {
+  fuchsia::ui::gfx::LayerArgs layer;
+
+  fuchsia::ui::gfx::ResourceArgs resource;
+  resource.set_layer(std::move(layer));
+
+  return NewCreateResourceCmd(id, std::move(resource));
+}
+
+fuchsia::ui::gfx::Command NewCreateSceneCmd(uint32_t id) {
+  fuchsia::ui::gfx::SceneArgs scene;
+
+  fuchsia::ui::gfx::ResourceArgs resource;
+  resource.set_scene(std::move(scene));
+
+  return NewCreateResourceCmd(id, std::move(resource));
+}
+
+fuchsia::ui::gfx::Command NewCreateCameraCmd(uint32_t id, uint32_t scene_id) {
+  fuchsia::ui::gfx::CameraArgs camera;
+  camera.scene_id = scene_id;
+
+  fuchsia::ui::gfx::ResourceArgs resource;
+  resource.set_camera(std::move(camera));
+
+  return NewCreateResourceCmd(id, std::move(resource));
+}
+
+fuchsia::ui::gfx::Command NewCreateStereoCameraCmd(uint32_t id,
+                                                   uint32_t scene_id) {
+  fuchsia::ui::gfx::StereoCameraArgs stereo_camera;
+  stereo_camera.scene_id = scene_id;
+
+  fuchsia::ui::gfx::ResourceArgs resource;
+  resource.set_stereo_camera(std::move(stereo_camera));
+
+  return NewCreateResourceCmd(id, std::move(resource));
+}
+
+fuchsia::ui::gfx::Command NewCreateRendererCmd(uint32_t id) {
+  fuchsia::ui::gfx::RendererArgs renderer;
+  fuchsia::ui::gfx::ResourceArgs resource;
+  resource.set_renderer(std::move(renderer));
+
+  return NewCreateResourceCmd(id, std::move(resource));
+}
+
+fuchsia::ui::gfx::Command NewCreateAmbientLightCmd(uint32_t id) {
+  fuchsia::ui::gfx::AmbientLightArgs ambient_light;
+
+  fuchsia::ui::gfx::ResourceArgs resource;
+  resource.set_ambient_light(std::move(ambient_light));
+
+  return NewCreateResourceCmd(id, std::move(resource));
+}
+
+fuchsia::ui::gfx::Command NewCreateDirectionalLightCmd(uint32_t id) {
+  fuchsia::ui::gfx::DirectionalLightArgs directional_light;
+
+  fuchsia::ui::gfx::ResourceArgs resource;
+  resource.set_directional_light(std::move(directional_light));
+
+  return NewCreateResourceCmd(id, std::move(resource));
+}
+
+fuchsia::ui::gfx::Command NewCreateCircleCmd(uint32_t id, float radius) {
+  fuchsia::ui::gfx::Value radius_value;
+  radius_value.set_vector1(radius);
+
+  fuchsia::ui::gfx::CircleArgs circle;
+  circle.radius = std::move(radius_value);
+
+  fuchsia::ui::gfx::ResourceArgs resource;
+  resource.set_circle(std::move(circle));
+
+  return NewCreateResourceCmd(id, std::move(resource));
+}
+
+fuchsia::ui::gfx::Command NewCreateRectangleCmd(uint32_t id, float width,
+                                                float height) {
+  fuchsia::ui::gfx::Value width_value;
+  width_value.set_vector1(width);
+
+  fuchsia::ui::gfx::Value height_value;
+  height_value.set_vector1(height);
+
+  fuchsia::ui::gfx::RectangleArgs rectangle;
+  rectangle.width = std::move(width_value);
+  rectangle.height = std::move(height_value);
+
+  fuchsia::ui::gfx::ResourceArgs resource;
+  resource.set_rectangle(std::move(rectangle));
+
+  return NewCreateResourceCmd(id, std::move(resource));
+}
+
+fuchsia::ui::gfx::Command NewCreateRoundedRectangleCmd(
+    uint32_t id, float width, float height, float top_left_radius,
+    float top_right_radius, float bottom_right_radius,
+    float bottom_left_radius) {
+  fuchsia::ui::gfx::Value width_value;
+  width_value.set_vector1(width);
+
+  fuchsia::ui::gfx::Value height_value;
+  height_value.set_vector1(height);
+
+  fuchsia::ui::gfx::Value top_left_radius_value;
+  top_left_radius_value.set_vector1(top_left_radius);
+
+  fuchsia::ui::gfx::Value top_right_radius_value;
+  top_right_radius_value.set_vector1(top_right_radius);
+
+  fuchsia::ui::gfx::Value bottom_right_radius_value;
+  bottom_right_radius_value.set_vector1(bottom_right_radius);
+
+  fuchsia::ui::gfx::Value bottom_left_radius_value;
+  bottom_left_radius_value.set_vector1(bottom_left_radius);
+
+  fuchsia::ui::gfx::RoundedRectangleArgs rectangle;
+  rectangle.width = std::move(width_value);
+  rectangle.height = std::move(height_value);
+  rectangle.top_left_radius = std::move(top_left_radius_value);
+  rectangle.top_right_radius = std::move(top_right_radius_value);
+  rectangle.bottom_right_radius = std::move(bottom_right_radius_value);
+  rectangle.bottom_left_radius = std::move(bottom_left_radius_value);
+
+  fuchsia::ui::gfx::ResourceArgs resource;
+  resource.set_rounded_rectangle(std::move(rectangle));
+
+  return NewCreateResourceCmd(id, std::move(resource));
+}
+
+fuchsia::ui::gfx::Command NewCreateVarCircleCmd(uint32_t id,
+                                                uint32_t radius_var_id,
+                                                uint32_t height_var_id) {
+  fuchsia::ui::gfx::Value radius_value;
+  radius_value.set_variable_id(radius_var_id);
+
+  fuchsia::ui::gfx::CircleArgs circle;
+  circle.radius = std::move(radius_value);
+
+  fuchsia::ui::gfx::ResourceArgs resource;
+  resource.set_circle(std::move(circle));
+
+  return NewCreateResourceCmd(id, std::move(resource));
+}
+
+fuchsia::ui::gfx::Command NewCreateVarRectangleCmd(uint32_t id,
+                                                   uint32_t width_var_id,
+                                                   uint32_t height_var_id) {
+  fuchsia::ui::gfx::Value width_value;
+  width_value.set_variable_id(width_var_id);
+
+  fuchsia::ui::gfx::Value height_value;
+  height_value.set_variable_id(height_var_id);
+
+  fuchsia::ui::gfx::RectangleArgs rectangle;
+  rectangle.width = std::move(width_value);
+  rectangle.height = std::move(height_value);
+
+  fuchsia::ui::gfx::ResourceArgs resource;
+  resource.set_rectangle(std::move(rectangle));
+
+  return NewCreateResourceCmd(id, std::move(resource));
+}
+
+fuchsia::ui::gfx::Command NewCreateVarRoundedRectangleCmd(
+    uint32_t id, uint32_t width_var_id, uint32_t height_var_id,
+    uint32_t top_left_radius_var_id, uint32_t top_right_radius_var_id,
+    uint32_t bottom_left_radius_var_id, uint32_t bottom_right_radius_var_id) {
+  fuchsia::ui::gfx::Value width_value;
+  width_value.set_variable_id(width_var_id);
+
+  fuchsia::ui::gfx::Value height_value;
+  height_value.set_variable_id(height_var_id);
+
+  fuchsia::ui::gfx::Value top_left_radius_value;
+  top_left_radius_value.set_variable_id(top_left_radius_var_id);
+
+  fuchsia::ui::gfx::Value top_right_radius_value;
+  top_right_radius_value.set_variable_id(top_right_radius_var_id);
+
+  fuchsia::ui::gfx::Value bottom_left_radius_value;
+  bottom_left_radius_value.set_variable_id(bottom_left_radius_var_id);
+
+  fuchsia::ui::gfx::Value bottom_right_radius_value;
+  bottom_right_radius_value.set_variable_id(bottom_right_radius_var_id);
+
+  fuchsia::ui::gfx::RoundedRectangleArgs rectangle;
+  rectangle.width = std::move(width_value);
+  rectangle.height = std::move(height_value);
+  rectangle.top_left_radius = std::move(top_left_radius_value);
+  rectangle.top_right_radius = std::move(top_right_radius_value);
+  rectangle.bottom_left_radius = std::move(bottom_left_radius_value);
+  rectangle.bottom_right_radius = std::move(bottom_right_radius_value);
+
+  fuchsia::ui::gfx::ResourceArgs resource;
+  resource.set_rounded_rectangle(std::move(rectangle));
+
+  return NewCreateResourceCmd(id, std::move(resource));
+}
+
+fuchsia::ui::gfx::Command NewCreateMeshCmd(uint32_t id) {
+  fuchsia::ui::gfx::MeshArgs mesh;
+
+  fuchsia::ui::gfx::ResourceArgs resource;
+  resource.set_mesh(std::move(mesh));
+
+  return NewCreateResourceCmd(id, std::move(resource));
+}
+
+fuchsia::ui::gfx::Command NewCreateMaterialCmd(uint32_t id) {
+  fuchsia::ui::gfx::MaterialArgs material;
+
+  fuchsia::ui::gfx::ResourceArgs resource;
+  resource.set_material(std::move(material));
+
+  return NewCreateResourceCmd(id, std::move(resource));
+}
+
+fuchsia::ui::gfx::Command NewCreateClipNodeCmd(uint32_t id) {
+  fuchsia::ui::gfx::ClipNodeArgs node;
+
+  fuchsia::ui::gfx::ResourceArgs resource;
+  resource.set_clip_node(std::move(node));
+
+  return NewCreateResourceCmd(id, std::move(resource));
+}
+
+fuchsia::ui::gfx::Command NewCreateEntityNodeCmd(uint32_t id) {
+  fuchsia::ui::gfx::EntityNodeArgs node;
+
+  fuchsia::ui::gfx::ResourceArgs resource;
+  resource.set_entity_node(std::move(node));
+
+  return NewCreateResourceCmd(id, std::move(resource));
+}
+
+fuchsia::ui::gfx::Command NewCreateOpacityNodeCmd(uint32_t id) {
+  fuchsia::ui::gfx::OpacityNodeArgs node;
+
+  fuchsia::ui::gfx::ResourceArgs resource;
+  resource.set_opacity_node(std::move(node));
+
+  return NewCreateResourceCmd(id, std::move(resource));
+}
+
+fuchsia::ui::gfx::Command NewCreateShapeNodeCmd(uint32_t id) {
+  fuchsia::ui::gfx::ShapeNodeArgs node;
+
+  fuchsia::ui::gfx::ResourceArgs resource;
+  resource.set_shape_node(std::move(node));
+
+  return NewCreateResourceCmd(id, std::move(resource));
+}
+
+fuchsia::ui::gfx::Command NewCreateViewCmd(uint32_t id, zx::eventpair token,
+                                           const std::string& debug_name) {
+  ZX_DEBUG_ASSERT(token);
+  fuchsia::ui::gfx::ViewArgs view;
+  view.token = std::move(token);
+  view.debug_name = debug_name;
+
+  fuchsia::ui::gfx::ResourceArgs resource;
+  resource.set_view(std::move(view));
+  return NewCreateResourceCmd(id, std::move(resource));
+}
+
+fuchsia::ui::gfx::Command NewCreateViewHolderCmd(
+    uint32_t id, zx::eventpair token, const std::string& debug_name) {
+  ZX_DEBUG_ASSERT(token);
+  fuchsia::ui::gfx::ViewHolderArgs view_holder;
+  view_holder.token = std::move(token);
+  view_holder.debug_name = debug_name;
+
+  fuchsia::ui::gfx::ResourceArgs resource;
+  resource.set_view_holder(std::move(view_holder));
+  return NewCreateResourceCmd(id, std::move(resource));
+}
+
+fuchsia::ui::gfx::Command NewCreateVariableCmd(uint32_t id,
+                                               fuchsia::ui::gfx::Value value) {
+  fuchsia::ui::gfx::VariableArgs variable;
+  switch (value.Which()) {
+    case ::fuchsia::ui::gfx::Value::Tag::kVector1:
+      variable.type = fuchsia::ui::gfx::ValueType::kVector1;
+      break;
+    case ::fuchsia::ui::gfx::Value::Tag::kVector2:
+      variable.type = fuchsia::ui::gfx::ValueType::kVector2;
+      break;
+    case ::fuchsia::ui::gfx::Value::Tag::kVector3:
+      variable.type = fuchsia::ui::gfx::ValueType::kVector3;
+      break;
+    case ::fuchsia::ui::gfx::Value::Tag::kVector4:
+      variable.type = fuchsia::ui::gfx::ValueType::kVector4;
+      break;
+    case fuchsia::ui::gfx::Value::Tag::kMatrix4x4:
+      variable.type = fuchsia::ui::gfx::ValueType::kMatrix4;
+      break;
+    case fuchsia::ui::gfx::Value::Tag::kColorRgba:
+      variable.type = fuchsia::ui::gfx::ValueType::kColorRgba;
+      break;
+    case fuchsia::ui::gfx::Value::Tag::kColorRgb:
+      variable.type = fuchsia::ui::gfx::ValueType::kColorRgb;
+      break;
+    case fuchsia::ui::gfx::Value::Tag::kDegrees:
+      variable.type = fuchsia::ui::gfx::ValueType::kVector1;
+      break;
+    case fuchsia::ui::gfx::Value::Tag::kTransform:
+      variable.type = fuchsia::ui::gfx::ValueType::kFactoredTransform;
+      break;
+    case fuchsia::ui::gfx::Value::Tag::kQuaternion:
+      variable.type = fuchsia::ui::gfx::ValueType::kQuaternion;
+      break;
+    case fuchsia::ui::gfx::Value::Tag::kVariableId:
+      // A variable's initial value cannot be another variable.
+      return fuchsia::ui::gfx::Command();
+    case fuchsia::ui::gfx::Value::Tag::Invalid:
+      return fuchsia::ui::gfx::Command();
+  }
+  variable.initial_value = std::move(value);
+
+  fuchsia::ui::gfx::ResourceArgs resource;
+  resource.set_variable(std::move(variable));
+
+  return NewCreateResourceCmd(id, std::move(resource));
+}
+
+fuchsia::ui::gfx::Command NewReleaseResourceCmd(uint32_t id) {
+  fuchsia::ui::gfx::ReleaseResourceCmd release_resource;
+  release_resource.id = id;
+
+  fuchsia::ui::gfx::Command command;
+  command.set_release_resource(std::move(release_resource));
+
+  return command;
+}
+
+fuchsia::ui::gfx::Command NewExportResourceCmd(uint32_t resource_id,
+                                               zx::eventpair export_token) {
+  ZX_DEBUG_ASSERT(export_token);
+
+  fuchsia::ui::gfx::ExportResourceCmd export_resource;
+  export_resource.id = resource_id;
+  export_resource.token = std::move(export_token);
+
+  fuchsia::ui::gfx::Command command;
+  command.set_export_resource(std::move(export_resource));
+
+  return command;
+}
+
+fuchsia::ui::gfx::Command NewImportResourceCmd(
+    uint32_t resource_id, fuchsia::ui::gfx::ImportSpec spec,
+    zx::eventpair import_token) {
+  ZX_DEBUG_ASSERT(import_token);
+
+  fuchsia::ui::gfx::ImportResourceCmd import_resource;
+  import_resource.id = resource_id;
+  import_resource.token = std::move(import_token);
+  import_resource.spec = spec;
+
+  fuchsia::ui::gfx::Command command;
+  command.set_import_resource(std::move(import_resource));
+
+  return command;
+}
+
+fuchsia::ui::gfx::Command NewExportResourceCmdAsRequest(
+    uint32_t resource_id, zx::eventpair* out_import_token) {
+  ZX_DEBUG_ASSERT(out_import_token);
+  ZX_DEBUG_ASSERT(!*out_import_token);
+
+  zx::eventpair export_token;
+  zx_status_t status =
+      zx::eventpair::create(0u, &export_token, out_import_token);
+  ZX_DEBUG_ASSERT_MSG(status == ZX_OK, "event pair create failed: status=%d",
+                      status);
+  return NewExportResourceCmd(resource_id, std::move(export_token));
+}
+
+fuchsia::ui::gfx::Command NewImportResourceCmdAsRequest(
+    uint32_t resource_id, fuchsia::ui::gfx::ImportSpec import_spec,
+    zx::eventpair* out_export_token) {
+  ZX_DEBUG_ASSERT(out_export_token);
+  ZX_DEBUG_ASSERT(!*out_export_token);
+
+  zx::eventpair import_token;
+  zx_status_t status =
+      zx::eventpair::create(0u, &import_token, out_export_token);
+  ZX_DEBUG_ASSERT_MSG(status == ZX_OK, "event pair create failed: status=%d",
+                      status);
+  return NewImportResourceCmd(resource_id, import_spec,
+                              std::move(import_token));
+}
+
+fuchsia::ui::gfx::Command NewSetViewPropertiesCmd(
+    uint32_t view_holder_id, const float bounding_box_min[3],
+    const float bounding_box_max[3], const float inset_from_min[3],
+    const float inset_from_max[3]) {
+  fuchsia::ui::gfx::SetViewPropertiesCmd set_view_properties;
+  set_view_properties.view_holder_id = view_holder_id;
+  auto& props = set_view_properties.properties;
+  props.bounding_box.min = NewVector3(bounding_box_min);
+  props.bounding_box.max = NewVector3(bounding_box_max);
+  props.inset_from_min = NewVector3(inset_from_min);
+  props.inset_from_max = NewVector3(inset_from_max);
+
+  fuchsia::ui::gfx::Command command;
+  command.set_set_view_properties(std::move(set_view_properties));
+
+  return command;
+}
+
+fuchsia::ui::gfx::Command NewSetViewPropertiesCmd(
+    uint32_t view_holder_id, const fuchsia::ui::gfx::ViewProperties& props) {
+  fuchsia::ui::gfx::SetViewPropertiesCmd set_view_properties;
+  set_view_properties.view_holder_id = view_holder_id;
+  set_view_properties.properties = props;
+
+  fuchsia::ui::gfx::Command command;
+  command.set_set_view_properties(std::move(set_view_properties));
+
+  return command;
+}
+
+fuchsia::ui::gfx::Command NewAddChildCmd(uint32_t node_id, uint32_t child_id) {
+  fuchsia::ui::gfx::AddChildCmd add_child;
+  add_child.node_id = node_id;
+  add_child.child_id = child_id;
+
+  fuchsia::ui::gfx::Command command;
+  command.set_add_child(std::move(add_child));
+
+  return command;
+}
+
+fuchsia::ui::gfx::Command NewAddPartCmd(uint32_t node_id, uint32_t part_id) {
+  fuchsia::ui::gfx::AddPartCmd add_part;
+  add_part.node_id = node_id;
+  add_part.part_id = part_id;
+
+  fuchsia::ui::gfx::Command command;
+  command.set_add_part(std::move(add_part));
+
+  return command;
+}
+
+fuchsia::ui::gfx::Command NewDetachCmd(uint32_t id) {
+  fuchsia::ui::gfx::DetachCmd detach;
+  detach.id = id;
+
+  fuchsia::ui::gfx::Command command;
+  command.set_detach(std::move(detach));
+
+  return command;
+}
+
+fuchsia::ui::gfx::Command NewDetachChildrenCmd(uint32_t node_id) {
+  fuchsia::ui::gfx::DetachChildrenCmd detach_children;
+  detach_children.node_id = node_id;
+
+  fuchsia::ui::gfx::Command command;
+  command.set_detach_children(std::move(detach_children));
+
+  return command;
+}
+
+fuchsia::ui::gfx::Command NewSetTranslationCmd(uint32_t node_id,
+                                               const float translation[3]) {
+  fuchsia::ui::gfx::SetTranslationCmd set_translation;
+  set_translation.id = node_id;
+  set_translation.value = NewVector3Value(translation);
+
+  fuchsia::ui::gfx::Command command;
+  command.set_set_translation(std::move(set_translation));
+
+  return command;
+}
+
+fuchsia::ui::gfx::Command NewSetTranslationCmd(uint32_t node_id,
+                                               uint32_t variable_id) {
+  fuchsia::ui::gfx::SetTranslationCmd set_translation;
+  set_translation.id = node_id;
+  set_translation.value = NewVector3Value(variable_id);
+
+  fuchsia::ui::gfx::Command command;
+  command.set_set_translation(std::move(set_translation));
+
+  return command;
+}
+
+fuchsia::ui::gfx::Command NewSetScaleCmd(uint32_t node_id,
+                                         const float scale[3]) {
+  fuchsia::ui::gfx::SetScaleCmd set_scale;
+  set_scale.id = node_id;
+  set_scale.value = NewVector3Value(scale);
+
+  fuchsia::ui::gfx::Command command;
+  command.set_set_scale(std::move(set_scale));
+
+  return command;
+}
+
+fuchsia::ui::gfx::Command NewSetScaleCmd(uint32_t node_id,
+                                         uint32_t variable_id) {
+  fuchsia::ui::gfx::SetScaleCmd set_scale;
+  set_scale.id = node_id;
+  set_scale.value = NewVector3Value(variable_id);
+
+  fuchsia::ui::gfx::Command command;
+  command.set_set_scale(std::move(set_scale));
+
+  return command;
+}
+
+fuchsia::ui::gfx::Command NewSetRotationCmd(uint32_t node_id,
+                                            const float quaternion[4]) {
+  fuchsia::ui::gfx::SetRotationCmd set_rotation;
+  set_rotation.id = node_id;
+  set_rotation.value = NewQuaternionValue(quaternion);
+
+  fuchsia::ui::gfx::Command command;
+  command.set_set_rotation(std::move(set_rotation));
+
+  return command;
+}
+
+fuchsia::ui::gfx::Command NewSetRotationCmd(uint32_t node_id,
+                                            uint32_t variable_id) {
+  fuchsia::ui::gfx::SetRotationCmd set_rotation;
+  set_rotation.id = node_id;
+  set_rotation.value = NewQuaternionValue(variable_id);
+
+  fuchsia::ui::gfx::Command command;
+  command.set_set_rotation(std::move(set_rotation));
+
+  return command;
+}
+
+fuchsia::ui::gfx::Command NewSetAnchorCmd(uint32_t node_id,
+                                          const float anchor[3]) {
+  fuchsia::ui::gfx::SetAnchorCmd set_anchor;
+  set_anchor.id = node_id;
+  set_anchor.value = NewVector3Value(anchor);
+
+  fuchsia::ui::gfx::Command command;
+  command.set_set_anchor(std::move(set_anchor));
+
+  return command;
+}
+
+fuchsia::ui::gfx::Command NewSetAnchorCmd(uint32_t node_id,
+                                          uint32_t variable_id) {
+  fuchsia::ui::gfx::SetAnchorCmd set_anchor;
+  set_anchor.id = node_id;
+  set_anchor.value = NewVector3Value(variable_id);
+
+  fuchsia::ui::gfx::Command command;
+  command.set_set_anchor(std::move(set_anchor));
+
+  return command;
+}
+
+fuchsia::ui::gfx::Command NewSetOpacityCmd(uint32_t node_id, float opacity) {
+  fuchsia::ui::gfx::SetOpacityCmd set_opacity;
+  set_opacity.node_id = node_id;
+  set_opacity.opacity = opacity;
+
+  fuchsia::ui::gfx::Command command;
+  command.set_set_opacity(std::move(set_opacity));
+
+  return command;
+}
+
+fuchsia::ui::gfx::Command NewSendSizeChangeHintCmdHACK(
+    uint32_t node_id, float width_change_factor, float height_change_factor) {
+  fuchsia::ui::gfx::SendSizeChangeHintCmdHACK send_size_change_hint;
+  send_size_change_hint.node_id = node_id;
+  send_size_change_hint.width_change_factor = width_change_factor;
+  send_size_change_hint.height_change_factor = height_change_factor;
+
+  fuchsia::ui::gfx::Command command;
+  command.set_send_size_change_hint_hack(std::move(send_size_change_hint));
+
+  return command;
+}
+
+fuchsia::ui::gfx::Command NewSetShapeCmd(uint32_t node_id, uint32_t shape_id) {
+  fuchsia::ui::gfx::SetShapeCmd set_shape;
+  set_shape.node_id = node_id;
+  set_shape.shape_id = shape_id;
+
+  fuchsia::ui::gfx::Command command;
+  command.set_set_shape(std::move(set_shape));
+
+  return command;
+}
+
+fuchsia::ui::gfx::Command NewSetMaterialCmd(uint32_t node_id,
+                                            uint32_t material_id) {
+  fuchsia::ui::gfx::SetMaterialCmd set_material;
+  set_material.node_id = node_id;
+  set_material.material_id = material_id;
+
+  fuchsia::ui::gfx::Command command;
+  command.set_set_material(std::move(set_material));
+
+  return command;
+}
+
+fuchsia::ui::gfx::Command NewSetClipCmd(uint32_t node_id, uint32_t clip_id,
+                                        bool clip_to_self) {
+  fuchsia::ui::gfx::SetClipCmd set_clip;
+  set_clip.node_id = node_id;
+  set_clip.clip_id = clip_id;
+  set_clip.clip_to_self = clip_to_self;
+
+  fuchsia::ui::gfx::Command command;
+  command.set_set_clip(std::move(set_clip));
+
+  return command;
+}
+
+fuchsia::ui::gfx::Command NewSetTagCmd(uint32_t node_id, uint32_t tag_value) {
+  fuchsia::ui::gfx::SetTagCmd set_tag;
+  set_tag.node_id = node_id;
+  set_tag.tag_value = tag_value;
+
+  fuchsia::ui::gfx::Command command;
+  command.set_set_tag(std::move(set_tag));
+
+  return command;
+}
+
+fuchsia::ui::gfx::Command NewTakeSnapshotCmdHACK(
+    uint32_t node_id, fuchsia::ui::gfx::SnapshotCallbackHACKPtr callback) {
+  fuchsia::ui::gfx::TakeSnapshotCmdHACK snapshot_cmd;
+  snapshot_cmd.node_id = node_id;
+  snapshot_cmd.callback = std::move(callback);
+
+  fuchsia::ui::gfx::Command command;
+  command.set_take_snapshot_cmd(std::move(snapshot_cmd));
+
+  return command;
+}
+
+fuchsia::ui::gfx::Command NewSetHitTestBehaviorCmd(
+    uint32_t node_id, fuchsia::ui::gfx::HitTestBehavior hit_test_behavior) {
+  fuchsia::ui::gfx::SetHitTestBehaviorCmd set_hit_test_behavior;
+  set_hit_test_behavior.node_id = node_id;
+  set_hit_test_behavior.hit_test_behavior = hit_test_behavior;
+
+  fuchsia::ui::gfx::Command command;
+  command.set_set_hit_test_behavior(std::move(set_hit_test_behavior));
+
+  return command;
+}
+
+fuchsia::ui::gfx::Command NewSetCameraCmd(uint32_t renderer_id,
+                                          uint32_t camera_id) {
+  fuchsia::ui::gfx::SetCameraCmd set_camera;
+  set_camera.renderer_id = renderer_id;
+  set_camera.camera_id = camera_id;
+
+  fuchsia::ui::gfx::Command command;
+  command.set_set_camera(std::move(set_camera));
+  return command;
+}
+
+fuchsia::ui::gfx::Command NewSetTextureCmd(uint32_t material_id,
+                                           uint32_t texture_id) {
+  fuchsia::ui::gfx::SetTextureCmd set_texture;
+  set_texture.material_id = material_id;
+  set_texture.texture_id = texture_id;
+
+  fuchsia::ui::gfx::Command command;
+  command.set_set_texture(std::move(set_texture));
+  return command;
+}
+
+fuchsia::ui::gfx::Command NewSetColorCmd(uint32_t material_id, uint8_t red,
+                                         uint8_t green, uint8_t blue,
+                                         uint8_t alpha) {
+  fuchsia::ui::gfx::ColorRgbaValue color;
+  color.value.red = red;
+  color.value.green = green;
+  color.value.blue = blue;
+  color.value.alpha = alpha;
+  color.variable_id = 0;
+  fuchsia::ui::gfx::SetColorCmd set_color;
+  set_color.material_id = material_id;
+  set_color.color = std::move(color);
+
+  fuchsia::ui::gfx::Command command;
+  command.set_set_color(std::move(set_color));
+
+  return command;
+}
+
+fuchsia::ui::gfx::MeshVertexFormat NewMeshVertexFormat(
+    fuchsia::ui::gfx::ValueType position_type,
+    fuchsia::ui::gfx::ValueType normal_type,
+    fuchsia::ui::gfx::ValueType tex_coord_type) {
+  fuchsia::ui::gfx::MeshVertexFormat vertex_format;
+  vertex_format.position_type = position_type;
+  vertex_format.normal_type = normal_type;
+  vertex_format.tex_coord_type = tex_coord_type;
+  return vertex_format;
+}
+
+fuchsia::ui::gfx::Command NewBindMeshBuffersCmd(
+    uint32_t mesh_id, uint32_t index_buffer_id,
+    fuchsia::ui::gfx::MeshIndexFormat index_format, uint64_t index_offset,
+    uint32_t index_count, uint32_t vertex_buffer_id,
+    fuchsia::ui::gfx::MeshVertexFormat vertex_format, uint64_t vertex_offset,
+    uint32_t vertex_count, const float bounding_box_min[3],
+    const float bounding_box_max[3]) {
+  fuchsia::ui::gfx::BindMeshBuffersCmd bind_mesh_buffers;
+  bind_mesh_buffers.mesh_id = mesh_id;
+  bind_mesh_buffers.index_buffer_id = index_buffer_id;
+  bind_mesh_buffers.index_format = index_format;
+  bind_mesh_buffers.index_offset = index_offset;
+  bind_mesh_buffers.index_count = index_count;
+  bind_mesh_buffers.vertex_buffer_id = vertex_buffer_id;
+  bind_mesh_buffers.vertex_format = std::move(vertex_format);
+  bind_mesh_buffers.vertex_offset = vertex_offset;
+  bind_mesh_buffers.vertex_count = vertex_count;
+  auto& bbox = bind_mesh_buffers.bounding_box;
+  bbox.min.x = bounding_box_min[0];
+  bbox.min.y = bounding_box_min[1];
+  bbox.min.z = bounding_box_min[2];
+  bbox.max.x = bounding_box_max[0];
+  bbox.max.y = bounding_box_max[1];
+  bbox.max.z = bounding_box_max[2];
+
+  fuchsia::ui::gfx::Command command;
+  command.set_bind_mesh_buffers(std::move(bind_mesh_buffers));
+
+  return command;
+}
+
+fuchsia::ui::gfx::Command NewAddLayerCmd(uint32_t layer_stack_id,
+                                         uint32_t layer_id) {
+  fuchsia::ui::gfx::AddLayerCmd add_layer;
+  add_layer.layer_stack_id = layer_stack_id;
+  add_layer.layer_id = layer_id;
+
+  fuchsia::ui::gfx::Command command;
+  command.set_add_layer(std::move(add_layer));
+  return command;
+}
+
+fuchsia::ui::gfx::Command NewRemoveLayerCmd(uint32_t layer_stack_id,
+                                            uint32_t layer_id) {
+  fuchsia::ui::gfx::RemoveLayerCmd remove_layer;
+  remove_layer.layer_stack_id = layer_stack_id;
+  remove_layer.layer_id = layer_id;
+
+  fuchsia::ui::gfx::Command command;
+  command.set_remove_layer(std::move(remove_layer));
+  return command;
+}
+
+fuchsia::ui::gfx::Command NewRemoveAllLayersCmd(uint32_t layer_stack_id) {
+  fuchsia::ui::gfx::RemoveAllLayersCmd remove_all_layers;
+  remove_all_layers.layer_stack_id = layer_stack_id;
+
+  fuchsia::ui::gfx::Command command;
+  command.set_remove_all_layers(std::move(remove_all_layers));
+  return command;
+}
+
+fuchsia::ui::gfx::Command NewSetLayerStackCmd(uint32_t compositor_id,
+                                              uint32_t layer_stack_id) {
+  fuchsia::ui::gfx::SetLayerStackCmd set_layer_stack;
+  set_layer_stack.compositor_id = compositor_id;
+  set_layer_stack.layer_stack_id = layer_stack_id;
+
+  fuchsia::ui::gfx::Command command;
+  command.set_set_layer_stack(std::move(set_layer_stack));
+  return command;
+}
+
+fuchsia::ui::gfx::Command NewSetRendererCmd(uint32_t layer_id,
+                                            uint32_t renderer_id) {
+  fuchsia::ui::gfx::SetRendererCmd set_renderer;
+  set_renderer.layer_id = layer_id;
+  set_renderer.renderer_id = renderer_id;
+
+  fuchsia::ui::gfx::Command command;
+  command.set_set_renderer(std::move(set_renderer));
+  return command;
+}
+
+fuchsia::ui::gfx::Command NewSetRendererParamCmd(
+    uint32_t renderer_id, fuchsia::ui::gfx::RendererParam param) {
+  fuchsia::ui::gfx::SetRendererParamCmd param_command;
+  param_command.renderer_id = renderer_id;
+  param_command.param = std::move(param);
+
+  fuchsia::ui::gfx::Command command;
+  command.set_set_renderer_param(std::move(param_command));
+  return command;
+}
+
+fuchsia::ui::gfx::Command NewSetSizeCmd(uint32_t node_id, const float size[2]) {
+  fuchsia::ui::gfx::SetSizeCmd set_size;
+  set_size.id = node_id;
+  auto& value = set_size.value.value;
+  value.x = size[0];
+  value.y = size[1];
+  set_size.value.variable_id = 0;
+
+  fuchsia::ui::gfx::Command command;
+  command.set_set_size(std::move(set_size));
+
+  return command;
+}
+
+fuchsia::ui::gfx::Command NewSetCameraTransformCmd(uint32_t camera_id,
+                                                   const float eye_position[3],
+                                                   const float eye_look_at[3],
+                                                   const float eye_up[3]) {
+  fuchsia::ui::gfx::SetCameraTransformCmd set_command;
+  set_command.camera_id = camera_id;
+  set_command.eye_position = NewVector3Value(eye_position);
+  set_command.eye_look_at = NewVector3Value(eye_look_at);
+  set_command.eye_up = NewVector3Value(eye_up);
+
+  fuchsia::ui::gfx::Command command;
+  command.set_set_camera_transform(std::move(set_command));
+
+  return command;
+}
+
+fuchsia::ui::gfx::Command NewSetCameraProjectionCmd(uint32_t camera_id,
+                                                    const float fovy) {
+  fuchsia::ui::gfx::SetCameraProjectionCmd set_command;
+  set_command.camera_id = camera_id;
+  set_command.fovy = NewFloatValue(fovy);
+
+  fuchsia::ui::gfx::Command command;
+  command.set_set_camera_projection(std::move(set_command));
+
+  return command;
+}
+
+fuchsia::ui::gfx::Command NewSetStereoCameraProjectionCmd(
+    uint32_t camera_id, const float left_projection[16],
+    const float right_projection[16]) {
+  fuchsia::ui::gfx::SetStereoCameraProjectionCmd set_command;
+  set_command.camera_id = camera_id;
+  set_command.left_projection = NewMatrix4Value(left_projection);
+  set_command.right_projection = NewMatrix4Value(right_projection);
+
+  fuchsia::ui::gfx::Command command;
+  command.set_set_stereo_camera_projection(std::move(set_command));
+
+  return command;
+}
+
+fuchsia::ui::gfx::Command NewSetCameraPoseBufferCmd(uint32_t camera_id,
+                                                    uint32_t buffer_id,
+                                                    uint32_t num_entries,
+                                                    int64_t base_time,
+                                                    uint64_t time_interval) {
+  fuchsia::ui::gfx::SetCameraPoseBufferCmd set_command;
+  set_command.camera_id = camera_id;
+  set_command.buffer_id = buffer_id;
+  set_command.num_entries = num_entries;
+  set_command.base_time = base_time;
+  set_command.time_interval = time_interval;
+
+  fuchsia::ui::gfx::Command command;
+  command.set_set_camera_pose_buffer(std::move(set_command));
+
+  return command;
+}
+
+fuchsia::ui::gfx::Command NewSetLightColorCmd(uint32_t light_id,
+                                              const float rgb[3]) {
+  fuchsia::ui::gfx::SetLightColorCmd set_command;
+  set_command.light_id = light_id;
+  set_command.color = NewColorRgbValue(rgb[0], rgb[1], rgb[2]);
+
+  fuchsia::ui::gfx::Command command;
+  command.set_set_light_color(std::move(set_command));
+
+  return command;
+}
+
+fuchsia::ui::gfx::Command NewSetLightColorCmd(uint32_t light_id,
+                                              uint32_t variable_id) {
+  fuchsia::ui::gfx::SetLightColorCmd set_command;
+  set_command.light_id = light_id;
+  set_command.color = NewColorRgbValue(variable_id);
+
+  fuchsia::ui::gfx::Command command;
+  command.set_set_light_color(std::move(set_command));
+
+  return command;
+}
+
+fuchsia::ui::gfx::Command NewSetLightDirectionCmd(uint32_t light_id,
+                                                  const float dir[3]) {
+  fuchsia::ui::gfx::SetLightDirectionCmd set_command;
+  set_command.light_id = light_id;
+  set_command.direction = NewVector3Value(dir);
+
+  fuchsia::ui::gfx::Command command;
+  command.set_set_light_direction(std::move(set_command));
+
+  return command;
+}
+
+fuchsia::ui::gfx::Command NewSetLightDirectionCmd(uint32_t light_id,
+                                                  uint32_t variable_id) {
+  fuchsia::ui::gfx::SetLightDirectionCmd set_command;
+  set_command.light_id = light_id;
+  set_command.direction = NewVector3Value(variable_id);
+
+  fuchsia::ui::gfx::Command command;
+  command.set_set_light_direction(std::move(set_command));
+
+  return command;
+}
+
+fuchsia::ui::gfx::Command NewAddLightCmd(uint32_t scene_id, uint32_t light_id) {
+  fuchsia::ui::gfx::AddLightCmd add_light_command;
+  add_light_command.scene_id = scene_id;
+  add_light_command.light_id = light_id;
+
+  fuchsia::ui::gfx::Command command;
+  command.set_add_light(std::move(add_light_command));
+
+  return command;
+}
+
+fuchsia::ui::gfx::Command NewDetachLightCmd(uint32_t light_id) {
+  fuchsia::ui::gfx::DetachLightCmd detach_light_command;
+  detach_light_command.light_id = light_id;
+
+  fuchsia::ui::gfx::Command command;
+  command.set_detach_light(std::move(detach_light_command));
+
+  return command;
+}
+
+fuchsia::ui::gfx::Command NewDetachLightsCmd(uint32_t scene_id) {
+  fuchsia::ui::gfx::DetachLightsCmd detach_lights_command;
+  detach_lights_command.scene_id = scene_id;
+
+  fuchsia::ui::gfx::Command command;
+  command.set_detach_lights(std::move(detach_lights_command));
+
+  return command;
+}
+
+fuchsia::ui::gfx::Command NewSetEventMaskCmd(uint32_t resource_id,
+                                             uint32_t event_mask) {
+  fuchsia::ui::gfx::SetEventMaskCmd set_event_mask_command;
+  set_event_mask_command.id = resource_id;
+  set_event_mask_command.event_mask = event_mask;
+
+  fuchsia::ui::gfx::Command command;
+  command.set_set_event_mask(std::move(set_event_mask_command));
+
+  return command;
+}
+
+fuchsia::ui::gfx::Command NewSetLabelCmd(uint32_t resource_id,
+                                         const std::string& label) {
+  fuchsia::ui::gfx::SetLabelCmd set_label_command;
+  set_label_command.id = resource_id;
+  set_label_command.label = label.substr(0, fuchsia::ui::gfx::kLabelMaxLength);
+
+  fuchsia::ui::gfx::Command command;
+  command.set_set_label(std::move(set_label_command));
+
+  return command;
+}
+
+fuchsia::ui::gfx::Command NewSetDisableClippingCmd(uint32_t renderer_id,
+                                                   bool disable_clipping) {
+  fuchsia::ui::gfx::SetDisableClippingCmd set_disable_clipping_command;
+  set_disable_clipping_command.renderer_id = renderer_id;
+  set_disable_clipping_command.disable_clipping = disable_clipping;
+
+  fuchsia::ui::gfx::Command command;
+  command.set_set_disable_clipping(std::move(set_disable_clipping_command));
+
+  return command;
+}
+
+fuchsia::ui::gfx::FloatValue NewFloatValue(float value) {
+  fuchsia::ui::gfx::FloatValue val;
+  val.variable_id = 0;
+  val.value = value;
+  return val;
+}
+
+fuchsia::ui::gfx::vec2 NewVector2(const float value[2]) {
+  fuchsia::ui::gfx::vec2 val;
+  val.x = value[0];
+  val.y = value[1];
+  return val;
+}
+
+fuchsia::ui::gfx::Vector2Value NewVector2Value(const float value[2]) {
+  fuchsia::ui::gfx::Vector2Value val;
+  val.variable_id = 0;
+  val.value = NewVector2(value);
+  return val;
+}
+
+fuchsia::ui::gfx::Vector2Value NewVector2Value(uint32_t variable_id) {
+  fuchsia::ui::gfx::Vector2Value val;
+  val.variable_id = variable_id;
+  return val;
+}
+
+fuchsia::ui::gfx::vec3 NewVector3(const float value[3]) {
+  fuchsia::ui::gfx::vec3 val;
+  val.x = value[0];
+  val.y = value[1];
+  val.z = value[2];
+  return val;
+}
+
+fuchsia::ui::gfx::Vector3Value NewVector3Value(const float value[3]) {
+  fuchsia::ui::gfx::Vector3Value val;
+  val.variable_id = 0;
+  val.value = NewVector3(value);
+  return val;
+}
+
+fuchsia::ui::gfx::Vector3Value NewVector3Value(uint32_t variable_id) {
+  fuchsia::ui::gfx::Vector3Value val;
+  val.variable_id = variable_id;
+  return val;
+}
+
+fuchsia::ui::gfx::vec4 NewVector4(const float value[4]) {
+  fuchsia::ui::gfx::vec4 val;
+  val.x = value[0];
+  val.y = value[1];
+  val.z = value[2];
+  val.w = value[3];
+  return val;
+}
+
+fuchsia::ui::gfx::Vector4Value NewVector4Value(const float value[4]) {
+  fuchsia::ui::gfx::Vector4Value val;
+  val.variable_id = 0;
+  val.value = NewVector4(value);
+  return val;
+}
+
+fuchsia::ui::gfx::Vector4Value NewVector4Value(uint32_t variable_id) {
+  fuchsia::ui::gfx::Vector4Value val;
+  val.variable_id = variable_id;
+  return val;
+}
+
+fuchsia::ui::gfx::Quaternion NewQuaternion(const float value[4]) {
+  fuchsia::ui::gfx::Quaternion val;
+  val.x = value[0];
+  val.y = value[1];
+  val.z = value[2];
+  val.w = value[3];
+  return val;
+}
+
+fuchsia::ui::gfx::QuaternionValue NewQuaternionValue(const float value[4]) {
+  fuchsia::ui::gfx::QuaternionValue val;
+  val.variable_id = 0;
+  val.value = NewQuaternion(value);
+  return val;
+}
+
+fuchsia::ui::gfx::QuaternionValue NewQuaternionValue(uint32_t variable_id) {
+  fuchsia::ui::gfx::QuaternionValue val;
+  val.variable_id = variable_id;
+  return val;
+}
+
+fuchsia::ui::gfx::mat4 NewMatrix4(const float matrix[16]) {
+  fuchsia::ui::gfx::mat4 val;
+  val.matrix[0] = matrix[0];
+  val.matrix[1] = matrix[1];
+  val.matrix[2] = matrix[2];
+  val.matrix[3] = matrix[3];
+  val.matrix[4] = matrix[4];
+  val.matrix[5] = matrix[5];
+  val.matrix[6] = matrix[6];
+  val.matrix[7] = matrix[7];
+  val.matrix[8] = matrix[8];
+  val.matrix[9] = matrix[9];
+  val.matrix[10] = matrix[10];
+  val.matrix[11] = matrix[11];
+  val.matrix[12] = matrix[12];
+  val.matrix[13] = matrix[13];
+  val.matrix[14] = matrix[14];
+  val.matrix[15] = matrix[15];
+  return val;
+}
+
+fuchsia::ui::gfx::Matrix4Value NewMatrix4Value(const float matrix[16]) {
+  fuchsia::ui::gfx::Matrix4Value val;
+  val.variable_id = 0;
+  val.value = NewMatrix4(matrix);
+  return val;
+}
+
+fuchsia::ui::gfx::Matrix4Value NewMatrix4Value(uint32_t variable_id) {
+  fuchsia::ui::gfx::Matrix4Value val;
+  val.variable_id = variable_id;
+  return val;
+}
+
+fuchsia::ui::gfx::ColorRgbValue NewColorRgbValue(float red, float green,
+                                                 float blue) {
+  fuchsia::ui::gfx::ColorRgbValue val;
+  val.variable_id = 0;
+  auto& color = val.value;
+  color.red = red;
+  color.green = green;
+  color.blue = blue;
+
+  return val;
+}
+
+fuchsia::ui::gfx::ColorRgbValue NewColorRgbValue(uint32_t variable_id) {
+  fuchsia::ui::gfx::ColorRgbValue val;
+  val.variable_id = variable_id;
+
+  return val;
+}
+
+fuchsia::ui::gfx::ColorRgbaValue NewColorRgbaValue(const uint8_t value[4]) {
+  fuchsia::ui::gfx::ColorRgbaValue val;
+  val.variable_id = 0;
+  auto& color = val.value;
+  color.red = value[0];
+  color.green = value[1];
+  color.blue = value[2];
+  color.alpha = value[3];
+
+  return val;
+}
+
+fuchsia::ui::gfx::ColorRgbaValue NewColorRgbaValue(uint32_t variable_id) {
+  fuchsia::ui::gfx::ColorRgbaValue val;
+  val.variable_id = variable_id;
+
+  return val;
+}
+
+// TODO(mikejurka): this should be in an images util file
+bool ImageInfoEquals(const fuchsia::images::ImageInfo& a,
+                     const fuchsia::images::ImageInfo& b) {
+  return a.transform == b.transform && a.width == b.width &&
+         a.height == b.height && a.stride == b.stride &&
+         a.pixel_format == b.pixel_format && a.color_space == b.color_space &&
+         a.tiling == b.tiling && a.alpha_format == b.alpha_format;
+}
+
+}  // namespace scenic
diff --git a/pkg/scenic_cpp/host_image_cycler.cc b/pkg/scenic_cpp/host_image_cycler.cc
new file mode 100644
index 0000000..70b45d6
--- /dev/null
+++ b/pkg/scenic_cpp/host_image_cycler.cc
@@ -0,0 +1,65 @@
+// Copyright 2017 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "lib/ui/scenic/cpp/host_image_cycler.h"
+
+#include <zircon/assert.h>
+
+namespace scenic {
+
+HostImageCycler::HostImageCycler(Session* session)
+    : EntityNode(session),
+      content_node_(session),
+      content_material_(session),
+      image_pool_(session, kNumBuffers) {
+  content_node_.SetMaterial(content_material_);
+  AddChild(content_node_);
+}
+
+HostImageCycler::~HostImageCycler() = default;
+
+const HostImage* HostImageCycler::AcquireImage(
+    uint32_t width, uint32_t height, uint32_t stride,
+    fuchsia::images::PixelFormat pixel_format,
+    fuchsia::images::ColorSpace color_space) {
+  ZX_DEBUG_ASSERT(!acquired_image_);
+
+  // Update the image pool and content shape.
+  fuchsia::images::ImageInfo image_info;
+  image_info.width = width;
+  image_info.height = height;
+  image_info.stride = stride;
+  image_info.pixel_format = pixel_format;
+  image_info.color_space = color_space;
+  image_info.tiling = fuchsia::images::Tiling::LINEAR;
+  reconfigured_ = image_pool_.Configure(&image_info);
+
+  const HostImage* image = image_pool_.GetImage(image_index_);
+  ZX_DEBUG_ASSERT(image);
+  acquired_image_ = true;
+  return image;
+}
+
+void HostImageCycler::ReleaseAndSwapImage() {
+  ZX_DEBUG_ASSERT(acquired_image_);
+  acquired_image_ = false;
+
+  const HostImage* image = image_pool_.GetImage(image_index_);
+  ZX_DEBUG_ASSERT(image);
+  content_material_.SetTexture(*image);
+
+  if (reconfigured_) {
+    Rectangle content_rect(content_node_.session(),
+                           image_pool_.image_info()->width,
+                           image_pool_.image_info()->height);
+    content_node_.SetShape(content_rect);
+    reconfigured_ = false;
+  }
+
+  // TODO(MZ-145): Define an |InvalidateCmd| on |Image| instead.
+  image_pool_.DiscardImage(image_index_);
+  image_index_ = (image_index_ + 1) % kNumBuffers;
+}
+
+}  // namespace scenic
diff --git a/pkg/scenic_cpp/host_memory.cc b/pkg/scenic_cpp/host_memory.cc
new file mode 100644
index 0000000..d01e665
--- /dev/null
+++ b/pkg/scenic_cpp/host_memory.cc
@@ -0,0 +1,151 @@
+// Copyright 2017 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "lib/ui/scenic/cpp/host_memory.h"
+
+#include <lib/zx/vmar.h>
+#include <lib/zx/vmo.h>
+#include <zircon/assert.h>
+#include <memory>
+
+#include "lib/ui/scenic/cpp/commands.h"
+
+namespace scenic {
+namespace {
+
+// Returns true if a memory object is of an appropriate size to recycle.
+bool CanReuseMemory(const HostMemory& memory, size_t desired_size) {
+  return memory.data_size() >= desired_size &&
+         memory.data_size() <= desired_size * 2;
+}
+
+std::pair<zx::vmo, std::shared_ptr<HostData>> AllocateMemory(size_t size) {
+  // Create the vmo and map it into this process.
+  zx::vmo local_vmo;
+  zx_status_t status = zx::vmo::create(size, 0u, &local_vmo);
+  ZX_ASSERT_MSG(status == ZX_OK, "vmo create failed: status=%d", status);
+  auto data = std::make_shared<HostData>(local_vmo, 0u, size);
+
+  // Drop rights before we transfer the VMO to the session manager.
+  // TODO(MA-492): Now that host-local memory may be concurrently used as
+  // device-local memory on UMA platforms, we need to keep all permissions on
+  // the duplicated vmo handle, until Vulkan can import read-only memory.
+  zx::vmo remote_vmo;
+  status = local_vmo.replace(ZX_RIGHT_SAME_RIGHTS, &remote_vmo);
+  ZX_ASSERT_MSG(status == ZX_OK, "replace rights failed: status=%d", status);
+  return std::make_pair(std::move(remote_vmo), std::move(data));
+}
+
+}  // namespace
+
+HostData::HostData(const zx::vmo& vmo, off_t offset, size_t size)
+    : size_(size) {
+  static const uint32_t flags =
+      ZX_VM_FLAG_PERM_READ | ZX_VM_FLAG_PERM_WRITE | ZX_VM_FLAG_MAP_RANGE;
+  uintptr_t ptr;
+  zx_status_t status =
+      zx::vmar::root_self()->map(0, vmo, offset, size, flags, &ptr);
+  ZX_ASSERT_MSG(status == ZX_OK, "map failed: status=%d", status);
+  ptr_ = reinterpret_cast<void*>(ptr);
+}
+
+HostData::~HostData() {
+  zx_status_t status =
+      zx::vmar::root_self()->unmap(reinterpret_cast<uintptr_t>(ptr_), size_);
+  ZX_ASSERT_MSG(status == ZX_OK, "unmap failed: status=%d", status);
+}
+
+HostMemory::HostMemory(Session* session, size_t size)
+    : HostMemory(session, AllocateMemory(size)) {}
+
+HostMemory::HostMemory(Session* session,
+                       std::pair<zx::vmo, std::shared_ptr<HostData>> init)
+    : Memory(session, std::move(init.first), init.second->size(),
+             fuchsia::images::MemoryType::HOST_MEMORY),
+      data_(std::move(init.second)) {}
+
+HostMemory::HostMemory(HostMemory&& moved)
+    : Memory(std::move(moved)), data_(std::move(moved.data_)) {}
+
+HostMemory::~HostMemory() = default;
+
+HostImage::HostImage(const HostMemory& memory, off_t memory_offset,
+                     fuchsia::images::ImageInfo info)
+    : HostImage(memory.session(), memory.id(), memory_offset, memory.data(),
+                std::move(info)) {}
+
+HostImage::HostImage(Session* session, uint32_t memory_id, off_t memory_offset,
+                     std::shared_ptr<HostData> data,
+                     fuchsia::images::ImageInfo info)
+    : Image(session, memory_id, memory_offset, std::move(info)),
+      data_(std::move(data)) {}
+
+HostImage::HostImage(HostImage&& moved)
+    : Image(std::move(moved)), data_(std::move(moved.data_)) {}
+
+HostImage::~HostImage() = default;
+
+HostImagePool::HostImagePool(Session* session, uint32_t num_images)
+    : session_(session), image_ptrs_(num_images), memory_ptrs_(num_images) {}
+
+HostImagePool::~HostImagePool() = default;
+
+// TODO(mikejurka): Double-check these changes
+bool HostImagePool::Configure(const fuchsia::images::ImageInfo* image_info) {
+  if (image_info) {
+    if (configured_ && ImageInfoEquals(*image_info, image_info_)) {
+      return false;  // no change
+    }
+    configured_ = true;
+    image_info_ = *image_info;
+  } else {
+    if (!configured_) {
+      return false;  // no change
+    }
+    configured_ = false;
+  }
+
+  for (uint32_t i = 0; i < num_images(); i++)
+    image_ptrs_[i].reset();
+
+  if (configured_) {
+    ZX_DEBUG_ASSERT(image_info_.width > 0);
+    ZX_DEBUG_ASSERT(image_info_.height > 0);
+    ZX_DEBUG_ASSERT(image_info_.stride > 0);
+
+    size_t desired_size = Image::ComputeSize(image_info_);
+    for (uint32_t i = 0; i < num_images(); i++) {
+      if (memory_ptrs_[i] && !CanReuseMemory(*memory_ptrs_[i], desired_size))
+        memory_ptrs_[i].reset();
+    }
+  }
+  return true;
+}
+
+const HostImage* HostImagePool::GetImage(uint32_t index) {
+  ZX_DEBUG_ASSERT(index < num_images());
+
+  if (image_ptrs_[index])
+    return image_ptrs_[index].get();
+
+  if (!configured_)
+    return nullptr;
+
+  if (!memory_ptrs_[index]) {
+    memory_ptrs_[index] =
+        std::make_unique<HostMemory>(session_, Image::ComputeSize(image_info_));
+  }
+
+  image_ptrs_[index] =
+      std::make_unique<HostImage>(*memory_ptrs_[index], 0u, image_info_);
+  return image_ptrs_[index].get();
+}
+
+void HostImagePool::DiscardImage(uint32_t index) {
+  ZX_DEBUG_ASSERT(index < num_images());
+
+  image_ptrs_[index].reset();
+}
+
+}  // namespace scenic
diff --git a/pkg/scenic_cpp/include/lib/ui/scenic/cpp/commands.h b/pkg/scenic_cpp/include/lib/ui/scenic/cpp/commands.h
new file mode 100644
index 0000000..2c44a2f
--- /dev/null
+++ b/pkg/scenic_cpp/include/lib/ui/scenic/cpp/commands.h
@@ -0,0 +1,268 @@
+// Copyright 2017 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef LIB_UI_SCENIC_CPP_COMMANDS_H_
+#define LIB_UI_SCENIC_CPP_COMMANDS_H_
+
+#include <string>
+
+#include <fuchsia/images/cpp/fidl.h>
+#include <fuchsia/ui/gfx/cpp/fidl.h>
+#include <fuchsia/ui/scenic/cpp/fidl.h>
+
+namespace scenic {
+
+constexpr float kZeroesFloat3[3] = {0.f, 0.f, 0.f};
+constexpr float kOnesFloat3[3] = {1.f, 1.f, 1.f};
+// A quaterion that has no rotation.
+constexpr float kQuaternionDefault[4] = {0.f, 0.f, 0.f, 1.f};
+
+// Helper function for wrapping a GFX command as a Scenic command.
+fuchsia::ui::scenic::Command NewCommand(fuchsia::ui::gfx::Command command);
+
+// Helper function for wrapping an input command as a Scenic command.
+fuchsia::ui::scenic::Command NewCommand(fuchsia::ui::input::Command command);
+
+// Resource creation.
+fuchsia::ui::gfx::Command NewCreateMemoryCmd(
+    uint32_t id, zx::vmo vmo, uint64_t allocation_size,
+    fuchsia::images::MemoryType memory_type);
+fuchsia::ui::gfx::Command NewCreateImageCmd(uint32_t id, uint32_t memory_id,
+                                            uint32_t memory_offset,
+                                            fuchsia::images::ImageInfo info);
+fuchsia::ui::gfx::Command NewCreateImageCmd(
+    uint32_t id, uint32_t memory_id, uint32_t memory_offset,
+    fuchsia::images::PixelFormat format,
+    fuchsia::images::ColorSpace color_space, fuchsia::images::Tiling tiling,
+    uint32_t width, uint32_t height, uint32_t stride);
+fuchsia::ui::gfx::Command NewCreateImagePipeCmd(
+    uint32_t id, ::fidl::InterfaceRequest<fuchsia::images::ImagePipe> request);
+fuchsia::ui::gfx::Command NewCreateBufferCmd(uint32_t id, uint32_t memory_id,
+                                             uint32_t memory_offset,
+                                             uint32_t num_bytes);
+
+fuchsia::ui::gfx::Command NewCreateCompositorCmd(uint32_t id);
+fuchsia::ui::gfx::Command NewCreateDisplayCompositorCmd(uint32_t id);
+fuchsia::ui::gfx::Command NewCreateLayerStackCmd(uint32_t id);
+fuchsia::ui::gfx::Command NewCreateLayerCmd(uint32_t id);
+
+fuchsia::ui::gfx::Command NewCreateSceneCmd(uint32_t id);
+fuchsia::ui::gfx::Command NewCreateCameraCmd(uint32_t id, uint32_t scene_id);
+fuchsia::ui::gfx::Command NewCreateStereoCameraCmd(uint32_t id,
+                                                   uint32_t scene_id);
+fuchsia::ui::gfx::Command NewCreateRendererCmd(uint32_t id);
+fuchsia::ui::gfx::Command NewCreateAmbientLightCmd(uint32_t id);
+fuchsia::ui::gfx::Command NewCreateDirectionalLightCmd(uint32_t id);
+
+fuchsia::ui::gfx::Command NewCreateCircleCmd(uint32_t id, float radius);
+fuchsia::ui::gfx::Command NewCreateRectangleCmd(uint32_t id, float width,
+                                                float height);
+fuchsia::ui::gfx::Command NewCreateRoundedRectangleCmd(
+    uint32_t id, float width, float height, float top_left_radius,
+    float top_right_radius, float bottom_right_radius,
+    float bottom_left_radius);
+
+// Variant of NewCreateCircleCmd that uses a variable radius instead of a
+// constant one set at construction time.
+fuchsia::ui::gfx::Command NewCreateVarCircleCmd(uint32_t id,
+                                                uint32_t radius_var_id);
+// Variant of NewCreateRectangleCmd that uses a variable width/height
+// instead of constant ones set at construction time.
+fuchsia::ui::gfx::Command NewCreateVarRectangleCmd(uint32_t id,
+                                                   uint32_t width_var_id,
+                                                   uint32_t height_var_id);
+// Variant of NewCreateRoundedRectangleCmd that uses a variable
+// width/height/etc. instead of constant ones set at construction time.
+fuchsia::ui::gfx::Command NewCreateVarRoundedRectangleCmd(
+    uint32_t id, uint32_t width_var_id, uint32_t height_var_id,
+    uint32_t top_left_radius_var_id, uint32_t top_right_radius_var_id,
+    uint32_t bottom_left_radius_var_id, uint32_t bottom_right_radius_var_id);
+
+fuchsia::ui::gfx::Command NewCreateMeshCmd(uint32_t id);
+fuchsia::ui::gfx::Command NewCreateMaterialCmd(uint32_t id);
+fuchsia::ui::gfx::Command NewCreateClipNodeCmd(uint32_t id);
+fuchsia::ui::gfx::Command NewCreateEntityNodeCmd(uint32_t id);
+fuchsia::ui::gfx::Command NewCreateOpacityNodeCmd(uint32_t id);
+fuchsia::ui::gfx::Command NewCreateShapeNodeCmd(uint32_t id);
+fuchsia::ui::gfx::Command NewCreateViewCmd(uint32_t id, zx::eventpair token,
+                                           const std::string& debug_name);
+fuchsia::ui::gfx::Command NewCreateViewHolderCmd(uint32_t id,
+                                                 zx::eventpair token,
+                                                 const std::string& debug_name);
+fuchsia::ui::gfx::Command NewCreateVariableCmd(uint32_t id,
+                                               fuchsia::ui::gfx::Value value);
+
+fuchsia::ui::gfx::Command NewReleaseResourceCmd(uint32_t id);
+
+// Export & Import operations.
+fuchsia::ui::gfx::Command NewExportResourceCmd(uint32_t resource_id,
+                                               zx::eventpair export_token);
+fuchsia::ui::gfx::Command NewImportResourceCmd(
+    uint32_t resource_id, fuchsia::ui::gfx::ImportSpec spec,
+    zx::eventpair import_token);
+
+// Exports the resource and returns an import token in |out_import_token|
+// which allows it to be imported into other sessions.
+fuchsia::ui::gfx::Command NewExportResourceCmdAsRequest(
+    uint32_t resource_id, zx::eventpair* out_import_token);
+
+// Imports the resource and returns an export token in |out_export_token|
+// by which another session can export a resource to associate with this import.
+fuchsia::ui::gfx::Command NewImportResourceCmdAsRequest(
+    uint32_t resource_id, fuchsia::ui::gfx::ImportSpec import_spec,
+    zx::eventpair* out_export_token);
+
+// View/ViewHolder commands.
+fuchsia::ui::gfx::Command NewSetViewPropertiesCmd(
+    uint32_t view_holder_id, const float bounding_box_min[3],
+    const float bounding_box_max[3], const float inset_from_min[3],
+    const float inset_from_max[3]);
+fuchsia::ui::gfx::Command NewSetViewPropertiesCmd(
+    uint32_t view_holder_id, const fuchsia::ui::gfx::ViewProperties& props);
+
+// Node operations.
+fuchsia::ui::gfx::Command NewAddChildCmd(uint32_t node_id, uint32_t child_id);
+fuchsia::ui::gfx::Command NewAddPartCmd(uint32_t node_id, uint32_t part_id);
+fuchsia::ui::gfx::Command NewDetachCmd(uint32_t node_id);
+fuchsia::ui::gfx::Command NewDetachChildrenCmd(uint32_t node_id);
+fuchsia::ui::gfx::Command NewSetTranslationCmd(uint32_t node_id,
+                                               const float translation[3]);
+fuchsia::ui::gfx::Command NewSetTranslationCmd(uint32_t node_id,
+                                               uint32_t variable_id);
+fuchsia::ui::gfx::Command NewSetScaleCmd(uint32_t node_id,
+                                         const float scale[3]);
+fuchsia::ui::gfx::Command NewSetScaleCmd(uint32_t node_id,
+                                         uint32_t variable_id);
+fuchsia::ui::gfx::Command NewSetRotationCmd(uint32_t node_id,
+                                            const float quaternion[4]);
+fuchsia::ui::gfx::Command NewSetRotationCmd(uint32_t node_id,
+                                            uint32_t variable_id);
+fuchsia::ui::gfx::Command NewSetAnchorCmd(uint32_t node_id,
+                                          const float anchor[3]);
+fuchsia::ui::gfx::Command NewSetAnchorCmd(uint32_t node_id,
+                                          uint32_t variable_id);
+
+fuchsia::ui::gfx::Command NewSetOpacityCmd(uint32_t node_id, float opacity);
+fuchsia::ui::gfx::Command NewSendSizeChangeHintCmdHACK(
+    uint32_t node_id, float width_change_factor, float height_change_factor);
+fuchsia::ui::gfx::Command NewSetShapeCmd(uint32_t node_id, uint32_t shape_id);
+fuchsia::ui::gfx::Command NewSetMaterialCmd(uint32_t node_id,
+                                            uint32_t material_id);
+fuchsia::ui::gfx::Command NewSetClipCmd(uint32_t node_id, uint32_t clip_id,
+                                        bool clip_to_self);
+fuchsia::ui::gfx::Command NewSetTagCmd(uint32_t node_id, uint32_t tag_value);
+fuchsia::ui::gfx::Command NewSetHitTestBehaviorCmd(
+    uint32_t node_id, fuchsia::ui::gfx::HitTestBehavior hit_test_behavior);
+fuchsia::ui::gfx::Command NewTakeSnapshotCmdHACK(
+    uint32_t id, fuchsia::ui::gfx::SnapshotCallbackHACKPtr callback);
+
+// Camera and lighting operations.
+
+fuchsia::ui::gfx::Command NewSetCameraCmd(uint32_t renderer_id,
+                                          uint32_t camera_id);
+fuchsia::ui::gfx::Command NewSetCameraTransformCmd(uint32_t camera_id,
+                                                   const float eye_position[3],
+                                                   const float eye_look_at[3],
+                                                   const float eye_up[3]);
+fuchsia::ui::gfx::Command NewSetCameraProjectionCmd(uint32_t camera_id,
+                                                    const float fovy);
+
+fuchsia::ui::gfx::Command NewSetCameraPoseBufferCmd(uint32_t camera_id,
+                                                    uint32_t buffer_id,
+                                                    uint32_t num_entries,
+                                                    int64_t base_time,
+                                                    uint64_t time_interval);
+
+fuchsia::ui::gfx::Command NewSetStereoCameraProjectionCmd(
+    uint32_t camera_id, const float left_projection[16],
+    const float right_projection[16]);
+
+fuchsia::ui::gfx::Command NewSetLightColorCmd(uint32_t light_id,
+                                              const float rgb[3]);
+fuchsia::ui::gfx::Command NewSetLightColorCmd(uint32_t light_id,
+                                              uint32_t variable_id);
+fuchsia::ui::gfx::Command NewSetLightDirectionCmd(uint32_t light_id,
+                                                  const float direction[3]);
+fuchsia::ui::gfx::Command NewSetLightDirectionCmd(uint32_t light_id,
+                                                  uint32_t variable_id);
+fuchsia::ui::gfx::Command NewAddLightCmd(uint32_t scene_id, uint32_t light_id);
+fuchsia::ui::gfx::Command NewDetachLightCmd(uint32_t light_id);
+fuchsia::ui::gfx::Command NewDetachLightsCmd(uint32_t scene_id);
+
+// Material operations.
+fuchsia::ui::gfx::Command NewSetTextureCmd(uint32_t node_id, uint32_t image_id);
+fuchsia::ui::gfx::Command NewSetColorCmd(uint32_t node_id, uint8_t red,
+                                         uint8_t green, uint8_t blue,
+                                         uint8_t alpha);
+
+// Mesh operations.
+fuchsia::ui::gfx::MeshVertexFormat NewMeshVertexFormat(
+    fuchsia::ui::gfx::ValueType position_type,
+    fuchsia::ui::gfx::ValueType normal_type,
+    fuchsia::ui::gfx::ValueType tex_coord_type);
+// These arguments are documented in commands.fidl; see BindMeshBuffersCmd.
+fuchsia::ui::gfx::Command NewBindMeshBuffersCmd(
+    uint32_t mesh_id, uint32_t index_buffer_id,
+    fuchsia::ui::gfx::MeshIndexFormat index_format, uint64_t index_offset,
+    uint32_t index_count, uint32_t vertex_buffer_id,
+    fuchsia::ui::gfx::MeshVertexFormat vertex_format, uint64_t vertex_offset,
+    uint32_t vertex_count, const float bounding_box_min[3],
+    const float bounding_box_max[3]);
+
+// Layer / LayerStack / Compositor operations.
+fuchsia::ui::gfx::Command NewAddLayerCmd(uint32_t layer_stack_id,
+                                         uint32_t layer_id);
+fuchsia::ui::gfx::Command NewRemoveLayerCmd(uint32_t layer_stack_id,
+                                            uint32_t layer_id);
+fuchsia::ui::gfx::Command NewRemoveAllLayersCmd(uint32_t layer_stack_id);
+fuchsia::ui::gfx::Command NewSetLayerStackCmd(uint32_t compositor_id,
+                                              uint32_t layer_stack_id);
+fuchsia::ui::gfx::Command NewSetRendererCmd(uint32_t layer_id,
+                                            uint32_t renderer_id);
+fuchsia::ui::gfx::Command NewSetRendererParamCmd(
+    uint32_t renderer_id, fuchsia::ui::gfx::RendererParam param);
+fuchsia::ui::gfx::Command NewSetSizeCmd(uint32_t node_id, const float size[2]);
+
+// Event operations.
+fuchsia::ui::gfx::Command NewSetEventMaskCmd(uint32_t resource_id,
+                                             uint32_t event_mask);
+
+// Diagnostic operations.
+fuchsia::ui::gfx::Command NewSetLabelCmd(uint32_t resource_id,
+                                         const std::string& label);
+
+// Debugging operations.
+fuchsia::ui::gfx::Command NewSetDisableClippingCmd(uint32_t resource_id,
+                                                   bool disable_clipping);
+
+// Basic types.
+fuchsia::ui::gfx::FloatValue NewFloatValue(float value);
+fuchsia::ui::gfx::Vector2Value NewVector2Value(const float value[2]);
+fuchsia::ui::gfx::Vector2Value NewVector2Value(uint32_t variable_id);
+fuchsia::ui::gfx::Vector3Value NewVector3Value(const float value[3]);
+fuchsia::ui::gfx::Vector3Value NewVector3Value(uint32_t variable_id);
+fuchsia::ui::gfx::Vector4Value NewVector4Value(const float value[4]);
+fuchsia::ui::gfx::Vector4Value NewVector4Value(uint32_t variable_id);
+fuchsia::ui::gfx::QuaternionValue NewQuaternionValue(const float value[4]);
+fuchsia::ui::gfx::QuaternionValue NewQuaternionValue(uint32_t variable_id);
+fuchsia::ui::gfx::Matrix4Value NewMatrix4Value(const float value[16]);
+fuchsia::ui::gfx::Matrix4Value NewMatrix4Value(uint32_t variable_id);
+fuchsia::ui::gfx::ColorRgbValue NewColorRgbValue(float red, float green,
+                                                 float blue);
+fuchsia::ui::gfx::ColorRgbValue NewColorRgbValue(uint32_t variable_id);
+fuchsia::ui::gfx::ColorRgbaValue NewColorRgbaValue(const uint8_t value[4]);
+fuchsia::ui::gfx::ColorRgbaValue NewColorRgbaValue(uint32_t variable_id);
+fuchsia::ui::gfx::QuaternionValue NewQuaternionValue(const float value[4]);
+fuchsia::ui::gfx::vec2 NewVector2(const float value[2]);
+fuchsia::ui::gfx::vec3 NewVector3(const float value[3]);
+fuchsia::ui::gfx::vec4 NewVector4(const float value[4]);
+
+// Utilities.
+
+bool ImageInfoEquals(const fuchsia::images::ImageInfo& a,
+                     const fuchsia::images::ImageInfo& b);
+
+}  // namespace scenic
+
+#endif  // LIB_UI_SCENIC_CPP_COMMANDS_H_
diff --git a/pkg/scenic_cpp/include/lib/ui/scenic/cpp/host_image_cycler.h b/pkg/scenic_cpp/include/lib/ui/scenic/cpp/host_image_cycler.h
new file mode 100644
index 0000000..0e89ce4
--- /dev/null
+++ b/pkg/scenic_cpp/include/lib/ui/scenic/cpp/host_image_cycler.h
@@ -0,0 +1,50 @@
+// Copyright 2017 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef LIB_UI_SCENIC_CPP_HOST_IMAGE_CYCLER_H_
+#define LIB_UI_SCENIC_CPP_HOST_IMAGE_CYCLER_H_
+
+#include "lib/ui/scenic/cpp/host_memory.h"
+
+namespace scenic {
+
+// Creates a node which presents double-buffered content drawn to an image
+// in host memory.
+class HostImageCycler : public scenic::EntityNode {
+ public:
+  explicit HostImageCycler(scenic::Session* session);
+  ~HostImageCycler();
+
+  HostImageCycler(const HostImageCycler&) = delete;
+  HostImageCycler& operator=(const HostImageCycler&) = delete;
+
+  // Acquires an image for rendering.
+  // At most one image can be acquired at a time.
+  // The client is responsible for clearing the image.
+  const HostImage* AcquireImage(uint32_t width, uint32_t height,
+                                uint32_t stride,
+                                fuchsia::images::PixelFormat pixel_format =
+                                    fuchsia::images::PixelFormat::BGRA_8,
+                                fuchsia::images::ColorSpace color_space =
+                                    fuchsia::images::ColorSpace::SRGB);
+
+  // Releases the image most recently acquired using |AcquireImage()|.
+  // Sets the content node's texture to be backed by the image.
+  void ReleaseAndSwapImage();
+
+ private:
+  static constexpr uint32_t kNumBuffers = 2u;
+
+  scenic::ShapeNode content_node_;
+  scenic::Material content_material_;
+  scenic::HostImagePool image_pool_;
+
+  bool acquired_image_ = false;
+  bool reconfigured_ = false;
+  uint32_t image_index_ = 0u;
+};
+
+}  // namespace scenic
+
+#endif  // LIB_UI_SCENIC_CPP_HOST_IMAGE_CYCLER_H_
diff --git a/pkg/scenic_cpp/include/lib/ui/scenic/cpp/host_memory.h b/pkg/scenic_cpp/include/lib/ui/scenic/cpp/host_memory.h
new file mode 100644
index 0000000..6209422
--- /dev/null
+++ b/pkg/scenic_cpp/include/lib/ui/scenic/cpp/host_memory.h
@@ -0,0 +1,149 @@
+// Copyright 2017 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef LIB_UI_SCENIC_CPP_HOST_MEMORY_H_
+#define LIB_UI_SCENIC_CPP_HOST_MEMORY_H_
+
+#include <memory>
+#include <utility>
+#include <vector>
+
+#include <lib/zx/vmo.h>
+
+#include "lib/ui/scenic/cpp/resources.h"
+
+namespace scenic {
+
+// Provides access to data stored in a host-accessible shared memory region.
+// The memory is unmapped once all references to this object have been released.
+class HostData : public std::enable_shared_from_this<HostData> {
+ public:
+  // Maps a range of an existing VMO into memory.
+  HostData(const zx::vmo& vmo, off_t offset, size_t size);
+  ~HostData();
+
+  HostData(const HostData&) = delete;
+  HostData& operator=(const HostData&) = delete;
+
+  // Gets the size of the data in bytes.
+  size_t size() const { return size_; }
+
+  // Gets a pointer to the data.
+  void* ptr() const { return ptr_; }
+
+ private:
+  size_t const size_;
+  void* ptr_;
+};
+
+// Represents a host-accessible shared memory backed memory resource in a
+// session.  The memory is mapped read/write into this process and transferred
+// read-only to the scene manager.  The shared memory region is retained until
+// this object is destroyed.
+// TODO(MZ-268): Don't inherit from Memory, so that Memory can have a public
+// move constructor.
+// TODO(MA-492): The memory is currently not transferred read-only, as we may
+// choose to map it as device-local memory on UMA platforms, and Vulkan requires
+// a read/write vmo in order to successfully import the memory.
+class HostMemory final : public Memory {
+ public:
+  HostMemory(Session* session, size_t size);
+  HostMemory(HostMemory&& moved);
+  ~HostMemory();
+
+  HostMemory(const HostMemory&) = delete;
+  HostMemory& operator=(const HostMemory&) = delete;
+
+  // Gets a reference to the underlying shared memory region.
+  const std::shared_ptr<HostData>& data() const { return data_; }
+
+  // Gets the size of the data in bytes.
+  size_t data_size() const { return data_->size(); }
+
+  // Gets a pointer to the data.
+  void* data_ptr() const { return data_->ptr(); }
+
+ private:
+  explicit HostMemory(Session* session,
+                      std::pair<zx::vmo, std::shared_ptr<HostData>> init);
+
+  std::shared_ptr<HostData> data_;
+};
+
+// Represents an image resource backed by host-accessible shared memory bound to
+// a session.  The shared memory region is retained until this object is
+// destroyed.
+// TODO(MZ-268): Don't inherit from Image, so that Image can have a public move
+// constructor.
+class HostImage final : public Image {
+ public:
+  HostImage(const HostMemory& memory, off_t memory_offset,
+            fuchsia::images::ImageInfo info);
+  HostImage(Session* session, uint32_t memory_id, off_t memory_offset,
+            std::shared_ptr<HostData> data, fuchsia::images::ImageInfo info);
+  HostImage(HostImage&& moved);
+  ~HostImage();
+
+  HostImage(const HostImage&) = delete;
+  HostImage& operator=(const HostImage&) = delete;
+
+  // Gets a reference to the underlying shared memory region.
+  const std::shared_ptr<HostData>& data() const { return data_; }
+
+  // Gets a pointer to the image data.
+  void* image_ptr() const {
+    return static_cast<uint8_t*>(data_->ptr()) + memory_offset();
+  }
+
+ private:
+  std::shared_ptr<HostData> data_;
+};
+
+// Represents a pool of image resources backed by host-accessible shared memory
+// bound to a session.  All images in the pool must have the same layout.
+class HostImagePool {
+ public:
+  // Creates a pool which can supply up to |num_images| images on demand.
+  explicit HostImagePool(Session* session, uint32_t num_images);
+  ~HostImagePool();
+
+  HostImagePool(const HostImagePool&) = delete;
+  HostImagePool& operator=(const HostImagePool&) = delete;
+
+  // The number of images which this pool can manage.
+  uint32_t num_images() const { return image_ptrs_.size(); }
+
+  // Gets information about the images in the pool, or nullptr if the
+  // pool is not configured.
+  const fuchsia::images::ImageInfo* image_info() const { return &image_info_; }
+
+  // Sets the image information for images in the pool.
+  // Previously created images are released but their memory may be reused.
+  // If |image_info| is nullptr, the pool reverts to an non-configured state;
+  // all images are released but the memory is retained for recycling.
+  // Returns true if the configuration changed.
+  bool Configure(const fuchsia::images::ImageInfo* image_info);
+
+  // Gets the image with the specified index.
+  // The |index| must be between 0 and |num_images() - 1|.
+  // The returned pointer is valid until the image is discarded or the
+  // pool is reconfigured.  Returns nullptr if the pool is not configured.
+  const HostImage* GetImage(uint32_t index);
+
+  // Discards the image with the specified index but recycles its memory.
+  // The |index| must be between 0 and |num_images() - 1|.
+  void DiscardImage(uint32_t index);
+
+ private:
+  Session* const session_;
+
+  bool configured_ = false;
+  fuchsia::images::ImageInfo image_info_;
+  std::vector<std::unique_ptr<HostImage>> image_ptrs_;
+  std::vector<std::unique_ptr<HostMemory>> memory_ptrs_;
+};
+
+}  // namespace scenic
+
+#endif  // LIB_UI_SCENIC_CPP_HOST_MEMORY_H_
diff --git a/pkg/scenic_cpp/include/lib/ui/scenic/cpp/id.h b/pkg/scenic_cpp/include/lib/ui/scenic/cpp/id.h
new file mode 100644
index 0000000..a500046
--- /dev/null
+++ b/pkg/scenic_cpp/include/lib/ui/scenic/cpp/id.h
@@ -0,0 +1,17 @@
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef LIB_UI_SCENIC_CPP_ID_H_
+#define LIB_UI_SCENIC_CPP_ID_H_
+
+#include <cstdint>
+
+namespace scenic {
+
+using SessionId = uint64_t;
+using ResourceId = uint32_t;
+
+}  // namespace scenic
+
+#endif  // LIB_UI_SCENIC_CPP_ID_H_
diff --git a/pkg/scenic_cpp/include/lib/ui/scenic/cpp/resources.h b/pkg/scenic_cpp/include/lib/ui/scenic/cpp/resources.h
new file mode 100644
index 0000000..40d6b0c
--- /dev/null
+++ b/pkg/scenic_cpp/include/lib/ui/scenic/cpp/resources.h
@@ -0,0 +1,593 @@
+// Copyright 2017 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef LIB_UI_SCENIC_CPP_RESOURCES_H_
+#define LIB_UI_SCENIC_CPP_RESOURCES_H_
+
+#include "lib/ui/scenic/cpp/session.h"
+
+#include <zircon/assert.h>
+
+namespace scenic {
+
+// Represents a resource in a session with a dynamically allocated id.
+// The resource is released from the session when this object is destroyed
+// but it may still be in use within the session if other resources reference
+// it.
+// This type cannot be instantiated, please see subclasses.
+class Resource {
+ public:
+  // Gets the session which owns this resource.
+  Session* session() const {
+    ZX_DEBUG_ASSERT(session_);
+    return session_;
+  }
+
+  // Gets the resource's id.
+  uint32_t id() const { return id_; }
+
+  // Exports the resource and associates it with |export_token|.
+  void Export(zx::eventpair export_token);
+
+  // Exports the resource and returns an import token in |out_import_token|
+  // which allows it to be imported into other sessions.
+  void ExportAsRequest(zx::eventpair* out_import_token);
+
+  // Sets which events a resource should deliver to the session listener.
+  void SetEventMask(uint32_t event_mask);
+
+  // Sets a label to help developers identify the purpose of the resource
+  // when using diagnostic tools.
+  void SetLabel(const std::string& label);
+
+ protected:
+  explicit Resource(Session* session);
+  Resource(Resource&& moved);
+
+  Resource(const Resource&) = delete;
+  Resource& operator=(const Resource&) = delete;
+
+  virtual ~Resource();
+
+ private:
+  Session* const session_;
+  uint32_t const id_;
+};
+
+// Represents a memory resource in a session.
+// TODO(MZ-268): Make this class final, and add public move constructor.
+class Memory : public Resource {
+ public:
+  Memory(Session* session, zx::vmo vmo, uint64_t allocation_size,
+         fuchsia::images::MemoryType memory_type);
+  ~Memory();
+
+  // Gets the underlying VMO's memory type, indicating whether it represents
+  // host or GPU memory.
+  fuchsia::images::MemoryType memory_type() const { return memory_type_; }
+
+ protected:
+  Memory(Memory&& moved);
+
+ private:
+  fuchsia::images::MemoryType const memory_type_;
+};
+
+// Represents an abstract shape resource in a session.
+// This type cannot be instantiated, please see subclasses.
+class Shape : public Resource {
+ protected:
+  explicit Shape(Session* session);
+  Shape(Shape&& moved);
+  ~Shape();
+};
+
+// Represents a circle shape resource in a session.
+class Circle final : public Shape {
+ public:
+  Circle(Session* session, float radius);
+  Circle(Circle&& moved);
+  ~Circle();
+};
+
+// Represents a rectangle shape resource in a session.
+class Rectangle final : public Shape {
+ public:
+  Rectangle(Session* session, float width, float height);
+  Rectangle(Rectangle&& moved);
+  ~Rectangle();
+};
+
+// Represents a rounded rectangle shape resource in a session.
+class RoundedRectangle final : public Shape {
+ public:
+  RoundedRectangle(Session* session, float width, float height,
+                   float top_left_radius, float top_right_radius,
+                   float bottom_right_radius, float bottom_left_radius);
+  RoundedRectangle(RoundedRectangle&& moved);
+  ~RoundedRectangle();
+};
+
+// Represents an image resource in a session.
+// TODO(MZ-268): Make this class final, and add public move constructor.
+class Image : public Resource {
+ public:
+  // Creates an image resource bound to a session.
+  Image(const Memory& memory, off_t memory_offset,
+        fuchsia::images::ImageInfo info);
+  Image(Session* session, uint32_t memory_id, off_t memory_offset,
+        fuchsia::images::ImageInfo info);
+  ~Image();
+
+  // Returns the number of bytes needed to represent an image.
+  static size_t ComputeSize(const fuchsia::images::ImageInfo& image_info);
+
+  // Gets the byte offset of the image within its memory resource.
+  off_t memory_offset() const { return memory_offset_; }
+
+  // Gets information about the image's layout.
+  const fuchsia::images::ImageInfo& info() const { return info_; }
+
+ protected:
+  Image(Image&& moved);
+
+ private:
+  off_t const memory_offset_;
+  fuchsia::images::ImageInfo const info_;
+};
+
+// Represents a buffer that is immutably bound to a range of a memory resource.
+class Buffer final : public Resource {
+ public:
+  Buffer(const Memory& memory, off_t memory_offset, size_t buffer_size);
+  Buffer(Session* session, uint32_t memory_id, off_t memory_offset,
+         size_t buffer_size);
+  Buffer(Buffer&& moved);
+  ~Buffer();
+};
+
+// Represents a mesh resource in a session.  Before it can be rendered, it
+// must be bound to index and vertex arrays by calling the BindBuffers() method.
+class Mesh final : public Shape {
+ public:
+  Mesh(Session* session);
+  Mesh(Mesh&& moved);
+  ~Mesh();
+
+  // These arguments are documented in commands.fidl; see
+  // BindMeshBuffersCmd.
+  void BindBuffers(const Buffer& index_buffer,
+                   fuchsia::ui::gfx::MeshIndexFormat index_format,
+                   uint64_t index_offset, uint32_t index_count,
+                   const Buffer& vertex_buffer,
+                   fuchsia::ui::gfx::MeshVertexFormat vertex_format,
+                   uint64_t vertex_offset, uint32_t vertex_count,
+                   const float bounding_box_min[3],
+                   const float bounding_box_max[3]);
+};
+
+// Represents a material resource in a session.
+class Material final : public Resource {
+ public:
+  explicit Material(Session* session);
+  Material(Material&& moved);
+  ~Material();
+
+  // Sets the material's texture.
+  void SetTexture(const Image& image) {
+    ZX_DEBUG_ASSERT(session() == image.session());
+    SetTexture(image.id());
+  }
+  void SetTexture(uint32_t image_id);
+
+  // Sets the material's color.
+  void SetColor(uint8_t red, uint8_t green, uint8_t blue, uint8_t alpha);
+};
+
+// Represents an abstract node resource in a session.
+// This type cannot be instantiated, please see subclasses.
+class Node : public Resource {
+ public:
+  // Sets the node's transform properties.
+  void SetTranslation(float tx, float ty, float tz) {
+    SetTranslation((float[3]){tx, ty, tz});
+  }
+  void SetTranslation(const float translation[3]);
+  void SetTranslation(uint32_t variable_id);
+  void SetScale(float sx, float sy, float sz) {
+    SetScale((float[3]){sx, sy, sz});
+  }
+  void SetScale(const float scale[3]);
+  void SetScale(uint32_t variable_id);
+  void SetRotation(float qi, float qj, float qk, float qw) {
+    SetRotation((float[4]){qi, qj, qk, qw});
+  }
+  void SetRotation(const float quaternion[4]);
+  void SetRotation(uint32_t variable_id);
+  void SetAnchor(float ax, float ay, float az) {
+    SetAnchor((float[3]){ax, ay, az});
+  }
+  void SetAnchor(const float anchor[3]);
+  void SetAnchor(uint32_t variable_id);
+
+  void SendSizeChangeHint(float width_change_factor,
+                          float height_change_factor);
+
+  // Sets the node's tag value.
+  void SetTag(uint32_t tag_value);
+
+  // Sets the node's hit test behavior.
+  void SetHitTestBehavior(fuchsia::ui::gfx::HitTestBehavior hit_test_behavior);
+
+  // Detaches the node from its parent.
+  void Detach();
+
+ protected:
+  explicit Node(Session* session);
+  Node(Node&& moved);
+  ~Node();
+};
+
+// Represents an shape node resource in a session.
+class ShapeNode final : public Node {
+ public:
+  explicit ShapeNode(Session* session);
+  ShapeNode(ShapeNode&& moved);
+  ~ShapeNode();
+
+  // Sets the shape that the shape node should draw.
+  void SetShape(const Shape& shape) {
+    ZX_DEBUG_ASSERT(session() == shape.session());
+    SetShape(shape.id());
+  }
+  void SetShape(uint32_t shape_id);
+
+  // Sets the material with which to draw the shape.
+  void SetMaterial(const Material& material) {
+    ZX_DEBUG_ASSERT(session() == material.session());
+    SetMaterial(material.id());
+  }
+  void SetMaterial(uint32_t material_id);
+};
+
+// Abstract base class for nodes which can have child nodes.
+// This type cannot be instantiated, please see subclasses.
+class ContainerNode : public Node {
+ public:
+  // Adds a child to the node.
+  void AddChild(const Node& child) {
+    ZX_DEBUG_ASSERT(session() == child.session());
+    AddChild(child.id());
+  }
+  void AddChild(uint32_t child_node_id);
+
+  void AddPart(const Node& part) {
+    ZX_DEBUG_ASSERT(session() == part.session());
+    AddPart(part.id());
+  }
+  void AddPart(uint32_t part_node_id);
+
+  // Detaches all children from the node.
+  void DetachChildren();
+
+ protected:
+  explicit ContainerNode(Session* session);
+  ContainerNode(ContainerNode&& moved);
+  ~ContainerNode();
+};
+
+// Required by EntityNode::Attach().
+class ViewHolder;
+
+// Represents an entity node resource in a session.
+// TODO(MZ-268): Make this class final, and add public move constructor.
+class EntityNode : public ContainerNode {
+ public:
+  explicit EntityNode(Session* session);
+  ~EntityNode();
+
+  void SetClip(uint32_t clip_id, bool clip_to_self);
+
+  void Attach(const ViewHolder& view_holder);
+
+  void Snapshot(fuchsia::ui::gfx::SnapshotCallbackHACKPtr callback);
+};
+
+// Represents an imported node resource in a session.
+// The imported node is initially created in an unbound state and must
+// be bound immediately after creation, prior to use.
+class ImportNode final : public ContainerNode {
+ public:
+  explicit ImportNode(Session* session);
+  ImportNode(ImportNode&& moved);
+  ~ImportNode();
+
+  // Imports the node associated with |import_token|.
+  void Bind(zx::eventpair import_token);
+
+  // Imports the node and returns an export token in |out_export_token|
+  // by which another session can export a node to associate with this import.
+  void BindAsRequest(zx::eventpair* out_export_token);
+
+  // Returns true if the import has been bound.
+  bool is_bound() const { return is_bound_; }
+
+ private:
+  bool is_bound_ = false;
+};
+
+// Represents a proxy for a View which can be added to a scene graph in order
+// to embed the View within it.
+//
+// Each ViewHolder is linked to a paired View via a shared token.
+//
+// Usually the ViewHolder and its associated View exist in separate processes,
+// allowing a distributed scene graph to be constructed.
+class ViewHolder final : public Resource {
+ public:
+  ViewHolder(Session* session, zx::eventpair token,
+             const std::string& debug_name);
+  ~ViewHolder();
+
+  // Set properties of the attached view.
+
+  void SetViewProperties(float min_x, float min_y, float min_z, float max_x,
+                         float max_y, float max_z, float in_min_x,
+                         float in_min_y, float in_min_z, float in_max_x,
+                         float in_max_y, float in_max_z) {
+    SetViewProperties((float[3]){min_x, min_y, min_z},
+                      (float[3]){max_x, max_y, max_z},
+                      (float[3]){in_min_x, in_min_y, in_min_z},
+                      (float[3]){in_max_x, in_max_y, in_max_z});
+  }
+  void SetViewProperties(const float bounding_box_min[3],
+                         const float bounding_box_max[3],
+                         const float inset_from_min[3],
+                         const float inset_from_max[3]);
+  void SetViewProperties(const fuchsia::ui::gfx::ViewProperties& props);
+};
+
+// Represents a transform space which serves as a container for Nodes.  The
+// Nodes will have the Views' coordinate transform applied to their own, in
+// addition to being clipped to the Views' bounding box.
+class View final : public Resource {
+ public:
+  View(Session* session, zx::eventpair token, const std::string& debug_name);
+  ~View();
+
+  void AddChild(const Node& child) const;
+  void DetachChild(const Node& child) const;
+};
+
+// Creates a node that clips the contents of its hierarchy to the specified clip
+// shape.
+class ClipNode final : public ContainerNode {
+ public:
+  explicit ClipNode(Session* session);
+  ClipNode(ClipNode&& moved);
+  ~ClipNode();
+};
+
+// Creates a node that renders its hierarchy with the specified opacity.
+class OpacityNode final : public ContainerNode {
+ public:
+  explicit OpacityNode(Session* session);
+  OpacityNode(OpacityNode&& moved);
+  ~OpacityNode();
+
+  // The opacity with which to render the contents of the hierarchy rooted at
+  // this node. The opacity values are clamped 0.0 to 1.0.
+  void SetOpacity(float opacity);
+};
+
+// A value that can be used in place of a constant value.
+class Variable final : public Resource {
+ public:
+  explicit Variable(Session* session, fuchsia::ui::gfx::Value initial_value);
+  Variable(Variable&& moved);
+  ~Variable();
+};
+
+// Represents an abstract light resource in a session.
+// This type cannot be instantiated, please see subclasses.
+class Light : public Resource {
+ public:
+  // Sets the light's color.
+  void SetColor(float red, float green, float blue) {
+    SetColor((float[3]){red, green, blue});
+  }
+  void SetColor(const float rgb[3]);
+  void SetColor(uint32_t variable_id);
+
+  // Detach light from the scene it is attached to, if any.
+  void Detach();
+
+ protected:
+  explicit Light(Session* session);
+  Light(Light&& moved);
+  ~Light();
+};
+
+// Represents a directional light resource in a session.
+class AmbientLight final : public Light {
+ public:
+  explicit AmbientLight(Session* session);
+  AmbientLight(AmbientLight&& moved);
+  ~AmbientLight();
+};
+
+// Represents a directional light resource in a session.
+class DirectionalLight final : public Light {
+ public:
+  explicit DirectionalLight(Session* session);
+  DirectionalLight(DirectionalLight&& moved);
+  ~DirectionalLight();
+
+  // Sets the light's direction.
+  void SetDirection(float dx, float dy, float dz) {
+    SetDirection((float[3]){dx, dy, dz});
+  }
+  void SetDirection(const float direction[3]);
+  void SetDirection(uint32_t variable_id);
+};
+
+// Represents a scene resource in a session.
+class Scene final : public ContainerNode {
+ public:
+  explicit Scene(Session* session);
+  Scene(Scene&& moved);
+  ~Scene();
+
+  void AddLight(const Light& light) {
+    ZX_DEBUG_ASSERT(session() == light.session());
+    AddLight(light.id());
+  }
+  void AddLight(uint32_t light_id);
+  void DetachLights();
+
+ private:
+  void Detach() = delete;
+};
+
+class CameraBase : public Resource {
+ public:
+  CameraBase(Session* session) : Resource(session) {}
+  CameraBase(CameraBase&& moved) : Resource(std::move(moved)) {}
+  ~CameraBase() {}
+  // Sets the camera's view parameters.
+  void SetTransform(const float eye_position[3], const float eye_look_at[3],
+                    const float eye_up[3]);
+  // Sets the camera pose buffer
+  void SetPoseBuffer(const Buffer& buffer, uint32_t num_entries,
+                     int64_t base_time, uint64_t time_interval);
+};
+
+// Represents a camera resource in a session.
+class Camera : public CameraBase {
+ public:
+  explicit Camera(const Scene& scene);
+  Camera(Session* session, uint32_t scene_id);
+  Camera(Camera&& moved);
+  ~Camera();
+
+  // Sets the camera's projection parameters.
+  void SetProjection(const float fovy);
+};
+
+// Represents a StereoCamera resource in a session.
+class StereoCamera final : public CameraBase {
+ public:
+  explicit StereoCamera(const Scene& scene);
+  StereoCamera(Session* session, uint32_t scene_id);
+  StereoCamera(StereoCamera&& moved);
+  ~StereoCamera();
+
+  // Sets the camera's projection parameters.
+  void SetStereoProjection(const float left_projection[16],
+                           const float right_projection[16]);
+};
+
+// Represents a renderer resource in a session.
+class Renderer final : public Resource {
+ public:
+  explicit Renderer(Session* session);
+  Renderer(Renderer&& moved);
+  ~Renderer();
+
+  // Sets the camera whose view will be rendered.
+  void SetCamera(const Camera& camera) {
+    ZX_DEBUG_ASSERT(session() == camera.session());
+    SetCamera(camera.id());
+  }
+  void SetCamera(uint32_t camera_id);
+
+  void SetParam(fuchsia::ui::gfx::RendererParam param);
+
+  // Convenient wrapper for SetParam().
+  void SetShadowTechnique(fuchsia::ui::gfx::ShadowTechnique technique);
+
+  // Set whether clipping is disabled for this renderer.
+  // NOTE: disabling clipping only has a visual effect; hit-testing is not
+  // affected.
+  void SetDisableClipping(bool disable_clipping);
+};
+
+// Represents a layer resource in a session.
+class Layer final : public Resource {
+ public:
+  explicit Layer(Session* session);
+  Layer(Layer&& moved);
+  ~Layer();
+
+  // Sets the layer's XY translation and Z-order.
+  void SetTranslation(float tx, float ty, float tz) {
+    SetTranslation((float[3]){tx, ty, tz});
+  }
+  void SetTranslation(const float translation[3]);
+
+  void SetSize(float width, float height) {
+    SetSize((float[2]){width, height});
+  }
+  void SetSize(const float size[2]);
+
+  void SetRenderer(const Renderer& renderer) {
+    ZX_DEBUG_ASSERT(session() == renderer.session());
+    SetRenderer(renderer.id());
+  }
+  void SetRenderer(uint32_t renderer_id);
+};
+
+// Represents a layer-stack resource in a session.
+class LayerStack final : public Resource {
+ public:
+  explicit LayerStack(Session* session);
+  LayerStack(LayerStack&& moved);
+  ~LayerStack();
+
+  void AddLayer(const Layer& layer) {
+    ZX_DEBUG_ASSERT(session() == layer.session());
+    AddLayer(layer.id());
+  }
+  void AddLayer(uint32_t layer_id);
+  void RemoveLayer(const Layer& layer) {
+    ZX_DEBUG_ASSERT(session() == layer.session());
+    RemoveLayer(layer.id());
+  }
+  void RemoveLayer(uint32_t layer_id);
+  void RemoveAllLayers();
+};
+
+// Represents a display-compositor resource in a session.
+class DisplayCompositor final : public Resource {
+ public:
+  explicit DisplayCompositor(Session* session);
+  DisplayCompositor(DisplayCompositor&& moved);
+  ~DisplayCompositor();
+
+  // Sets the layer-stack that is to be composited.
+  void SetLayerStack(const LayerStack& layer_stack) {
+    ZX_DEBUG_ASSERT(session() == layer_stack.session());
+    SetLayerStack(layer_stack.id());
+  }
+  void SetLayerStack(uint32_t layer_stack_id);
+};
+
+// Represents a display-less compositor resource in a session.
+class Compositor final : public Resource {
+ public:
+  explicit Compositor(Session* session);
+  Compositor(Compositor&& moved);
+  ~Compositor();
+
+  // Sets the layer-stack that is to be composited.
+  void SetLayerStack(const LayerStack& layer_stack) {
+    ZX_DEBUG_ASSERT(session() == layer_stack.session());
+    SetLayerStack(layer_stack.id());
+  }
+  void SetLayerStack(uint32_t layer_stack_id);
+};
+
+}  // namespace scenic
+
+#endif  // LIB_UI_SCENIC_CPP_RESOURCES_H_
diff --git a/pkg/scenic_cpp/include/lib/ui/scenic/cpp/session.h b/pkg/scenic_cpp/include/lib/ui/scenic/cpp/session.h
new file mode 100644
index 0000000..3455d15
--- /dev/null
+++ b/pkg/scenic_cpp/include/lib/ui/scenic/cpp/session.h
@@ -0,0 +1,148 @@
+// Copyright 2017 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef LIB_UI_SCENIC_CPP_SESSION_H_
+#define LIB_UI_SCENIC_CPP_SESSION_H_
+
+#include <fuchsia/images/cpp/fidl.h>
+#include <fuchsia/ui/gfx/cpp/fidl.h>
+#include <fuchsia/ui/input/cpp/fidl.h>
+#include <fuchsia/ui/scenic/cpp/fidl.h>
+#include <lib/fit/function.h>
+#include <lib/zx/event.h>
+
+#include <utility>
+
+#include "lib/fidl/cpp/binding.h"
+
+namespace scenic {
+
+// Connect to Scenic and establish a new Session, as well as an InterfaceRequest
+// for a SessionListener that can be hooked up as desired.
+using SessionPtrAndListenerRequest =
+    std::pair<fuchsia::ui::scenic::SessionPtr,
+              fidl::InterfaceRequest<fuchsia::ui::scenic::SessionListener>>;
+SessionPtrAndListenerRequest CreateScenicSessionPtrAndListenerRequest(
+    fuchsia::ui::scenic::Scenic* scenic);
+
+// Wraps a Scenic session.
+// Maintains a queue of pending operations and assists with allocation of
+// resource ids.
+class Session : private fuchsia::ui::scenic::SessionListener {
+ public:
+  // Provides timing information about a presentation request which has
+  // been applied by the scene manager.
+  using PresentCallback =
+      fit::function<void(fuchsia::images::PresentationInfo info)>;
+
+  // Provide information about hits.
+  using HitTestCallback =
+      fit::function<void(fidl::VectorPtr<fuchsia::ui::gfx::Hit> hits)>;
+
+  // Called when session events are received.
+  using EventHandler =
+      fit::function<void(fidl::VectorPtr<fuchsia::ui::scenic::Event>)>;
+
+  // Wraps the provided session and session listener.
+  // The listener is optional.
+  explicit Session(fuchsia::ui::scenic::SessionPtr session,
+                   fidl::InterfaceRequest<fuchsia::ui::scenic::SessionListener>
+                       session_listener = nullptr);
+
+  // Creates a new session using the provided Scenic and binds the listener to
+  // this object. The Scenic itself is not retained after construction.
+  explicit Session(fuchsia::ui::scenic::Scenic* scenic);
+
+  explicit Session(SessionPtrAndListenerRequest session_and_listener);
+
+  Session(const Session&) = delete;
+  Session& operator=(const Session&) = delete;
+
+  // Destroys the session.
+  // All resources must be released prior to destruction.
+  ~Session();
+
+  void set_error_handler(fit::function<void(zx_status_t)> closure) {
+    session_.set_error_handler(std::move(closure));
+  }
+
+  // Sets a callback which is invoked when events are received.
+  void set_event_handler(EventHandler event_handler) {
+    event_handler_ = std::move(event_handler);
+  }
+
+  // Gets a pointer to the underlying session interface.
+  fuchsia::ui::scenic::Session* session() { return session_.get(); }
+
+  // Allocates a new unique resource id.
+  uint32_t AllocResourceId();
+
+  // Enqueues an operation to release a resource.
+  void ReleaseResource(uint32_t resource_id);
+
+  // Enqueues an operation.
+  // The session will queue operations locally to batch submission of operations
+  // until |Flush()| or |Present()| is called.
+  void Enqueue(fuchsia::ui::scenic::Command command);
+  void Enqueue(fuchsia::ui::gfx::Command command);
+  void Enqueue(fuchsia::ui::input::Command command);
+
+  // Registers an acquire fence to be submitted during the subsequent call to
+  // |Present()|.
+  void EnqueueAcquireFence(zx::event fence);
+
+  // Registers a release fence to be submitted during the subsequent call to
+  // |Present()|.
+  void EnqueueReleaseFence(zx::event fence);
+
+  // Flushes queued operations to the session.
+  void Flush();
+
+  // Presents all previously enqueued operations.
+  // Implicitly flushes all queued operations to the session.
+  // Invokes the callback when the scene manager applies the presentation.
+  void Present(uint64_t presentation_time, PresentCallback callback);
+
+  // Performs a hit test along the specified ray.
+  void HitTest(uint32_t node_id, const float ray_origin[3],
+               const float ray_direction[3], HitTestCallback callback);
+
+  // Performs a hit test along the specified ray into the engine's first
+  // compositor.
+  void HitTestDeviceRay(
+      const float ray_origin[3], const float ray_direction[3],
+      fuchsia::ui::scenic::Session::HitTestDeviceRayCallback callback);
+
+  // Unbinds the internal SessionPtr; this allows moving this across threads.
+  void Unbind();
+
+  // Rebinds the Session interface internally; this must be called after a call
+  // to Unbind().
+  void Rebind();
+
+  void SetDebugName(const std::string& debug_name);
+
+ private:
+  // |fuchsia::ui::scenic::SessionListener|
+  void OnScenicError(fidl::StringPtr error) override;
+  void OnScenicEvent(
+      fidl::VectorPtr<fuchsia::ui::scenic::Event> events) override;
+
+  fuchsia::ui::scenic::SessionPtr session_;
+  // |session_handle_| is stored only when |session_| is unbound/invalid.
+  fidl::InterfaceHandle<fuchsia::ui::scenic::Session> session_handle_;
+  uint32_t next_resource_id_ = 1u;
+  uint32_t resource_count_ = 0u;
+
+  fidl::VectorPtr<fuchsia::ui::scenic::Command> commands_;
+  fidl::VectorPtr<zx::event> acquire_fences_;
+  fidl::VectorPtr<zx::event> release_fences_;
+
+  EventHandler event_handler_;
+  fidl::Binding<fuchsia::ui::scenic::SessionListener> session_listener_binding_;
+};
+
+}  // namespace scenic
+
+#endif  // LIB_UI_SCENIC_CPP_SESSION_H_
diff --git a/pkg/scenic_cpp/meta.json b/pkg/scenic_cpp/meta.json
new file mode 100644
index 0000000..3c966c8
--- /dev/null
+++ b/pkg/scenic_cpp/meta.json
@@ -0,0 +1,31 @@
+{
+  "deps": [
+    "fidl_cpp", 
+    "images_cpp", 
+    "fit", 
+    "zx"
+  ], 
+  "fidl_deps": [
+    "fuchsia.ui.gfx", 
+    "fuchsia.ui.scenic"
+  ], 
+  "headers": [
+    "pkg/scenic_cpp/include/lib/ui/scenic/cpp/commands.h", 
+    "pkg/scenic_cpp/include/lib/ui/scenic/cpp/host_image_cycler.h", 
+    "pkg/scenic_cpp/include/lib/ui/scenic/cpp/host_memory.h", 
+    "pkg/scenic_cpp/include/lib/ui/scenic/cpp/id.h", 
+    "pkg/scenic_cpp/include/lib/ui/scenic/cpp/resources.h", 
+    "pkg/scenic_cpp/include/lib/ui/scenic/cpp/session.h"
+  ], 
+  "include_dir": "pkg/scenic_cpp/include", 
+  "name": "scenic_cpp", 
+  "root": "pkg/scenic_cpp", 
+  "sources": [
+    "pkg/scenic_cpp/commands.cc", 
+    "pkg/scenic_cpp/host_image_cycler.cc", 
+    "pkg/scenic_cpp/host_memory.cc", 
+    "pkg/scenic_cpp/resources.cc", 
+    "pkg/scenic_cpp/session.cc"
+  ], 
+  "type": "cc_source_library"
+}
\ No newline at end of file
diff --git a/pkg/scenic_cpp/resources.cc b/pkg/scenic_cpp/resources.cc
new file mode 100644
index 0000000..58ab0d5
--- /dev/null
+++ b/pkg/scenic_cpp/resources.cc
@@ -0,0 +1,570 @@
+// Copyright 2017 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "lib/ui/scenic/cpp/resources.h"
+
+#include <algorithm>
+
+#include "lib/images/cpp/images.h"
+#include "lib/ui/scenic/cpp/commands.h"
+
+namespace scenic {
+namespace {
+
+template <class T>
+constexpr const T& clamp(const T& v, const T& lo, const T& hi) {
+  return (v < lo) ? lo : (hi < v) ? hi : v;
+}
+
+}  // namespace
+
+Resource::Resource(Session* session)
+    : session_(session), id_(session->AllocResourceId()) {}
+
+Resource::Resource(Resource&& moved)
+    : session_(moved.session_), id_(moved.id_) {
+  auto& moved_session = *const_cast<Session**>(&moved.session_);
+  auto& moved_id = *const_cast<uint32_t*>(&moved.id_);
+  moved_session = nullptr;
+  moved_id = 0;
+}
+
+Resource::~Resource() {
+  // If this resource was moved, it is not responsible for releasing the ID.
+  if (session_)
+    session_->ReleaseResource(id_);
+}
+
+void Resource::Export(zx::eventpair export_token) {
+  session_->Enqueue(NewExportResourceCmd(id(), std::move(export_token)));
+}
+
+void Resource::ExportAsRequest(zx::eventpair* out_import_token) {
+  session_->Enqueue(NewExportResourceCmdAsRequest(id(), out_import_token));
+}
+
+void Resource::SetEventMask(uint32_t event_mask) {
+  session_->Enqueue(NewSetEventMaskCmd(id(), event_mask));
+}
+
+void Resource::SetLabel(const std::string& label) {
+  session_->Enqueue(NewSetLabelCmd(id(), label));
+}
+
+Shape::Shape(Session* session) : Resource(session) {}
+
+Shape::Shape(Shape&& moved) : Resource(std::move(moved)) {}
+
+Shape::~Shape() = default;
+
+Circle::Circle(Session* session, float radius) : Shape(session) {
+  session->Enqueue(NewCreateCircleCmd(id(), radius));
+}
+
+Circle::Circle(Circle&& moved) : Shape(std::move(moved)) {}
+
+Circle::~Circle() = default;
+
+Rectangle::Rectangle(Session* session, float width, float height)
+    : Shape(session) {
+  session->Enqueue(NewCreateRectangleCmd(id(), width, height));
+}
+
+Rectangle::Rectangle(Rectangle&& moved) : Shape(std::move(moved)) {}
+
+Rectangle::~Rectangle() = default;
+
+RoundedRectangle::RoundedRectangle(Session* session, float width, float height,
+                                   float top_left_radius,
+                                   float top_right_radius,
+                                   float bottom_right_radius,
+                                   float bottom_left_radius)
+    : Shape(session) {
+  session->Enqueue(NewCreateRoundedRectangleCmd(
+      id(), width, height, top_left_radius, top_right_radius,
+      bottom_right_radius, bottom_left_radius));
+}
+
+RoundedRectangle::RoundedRectangle(RoundedRectangle&& moved)
+    : Shape(std::move(moved)) {}
+
+RoundedRectangle::~RoundedRectangle() = default;
+
+Image::Image(const Memory& memory, off_t memory_offset,
+             fuchsia::images::ImageInfo info)
+    : Image(memory.session(), memory.id(), memory_offset, std::move(info)) {}
+
+Image::Image(Session* session, uint32_t memory_id, off_t memory_offset,
+             fuchsia::images::ImageInfo info)
+    : Resource(session), memory_offset_(memory_offset), info_(info) {
+  session->Enqueue(
+      NewCreateImageCmd(id(), memory_id, memory_offset_, std::move(info)));
+}
+
+Image::Image(Image&& moved)
+    : Resource(std::move(moved)),
+      memory_offset_(moved.memory_offset_),
+      info_(moved.info_) {}
+
+Image::~Image() = default;
+
+size_t Image::ComputeSize(const fuchsia::images::ImageInfo& image_info) {
+  return images::ImageSize(image_info);
+}
+
+Buffer::Buffer(const Memory& memory, off_t memory_offset, size_t num_bytes)
+    : Buffer(memory.session(), memory.id(), memory_offset, num_bytes) {}
+
+Buffer::Buffer(Session* session, uint32_t memory_id, off_t memory_offset,
+               size_t num_bytes)
+    : Resource(session) {
+  session->Enqueue(
+      NewCreateBufferCmd(id(), memory_id, memory_offset, num_bytes));
+}
+
+Buffer::Buffer(Buffer&& moved) : Resource(std::move(moved)) {}
+
+Buffer::~Buffer() = default;
+
+Memory::Memory(Session* session, zx::vmo vmo, uint64_t allocation_size,
+               fuchsia::images::MemoryType memory_type)
+    : Resource(session), memory_type_(memory_type) {
+  session->Enqueue(
+      NewCreateMemoryCmd(id(), std::move(vmo), allocation_size, memory_type));
+}
+
+Memory::Memory(Memory&& moved)
+    : Resource(std::move(moved)), memory_type_(moved.memory_type_) {}
+
+Memory::~Memory() = default;
+
+Mesh::Mesh(Session* session) : Shape(session) {
+  session->Enqueue(NewCreateMeshCmd(id()));
+}
+
+Mesh::Mesh(Mesh&& moved) : Shape(std::move(moved)) {}
+
+Mesh::~Mesh() = default;
+
+void Mesh::BindBuffers(const Buffer& index_buffer,
+                       fuchsia::ui::gfx::MeshIndexFormat index_format,
+                       uint64_t index_offset, uint32_t index_count,
+                       const Buffer& vertex_buffer,
+                       fuchsia::ui::gfx::MeshVertexFormat vertex_format,
+                       uint64_t vertex_offset, uint32_t vertex_count,
+                       const float bounding_box_min[3],
+                       const float bounding_box_max[3]) {
+  ZX_DEBUG_ASSERT(session() == index_buffer.session() &&
+                  session() == vertex_buffer.session());
+  session()->Enqueue(NewBindMeshBuffersCmd(
+      id(), index_buffer.id(), index_format, index_offset, index_count,
+      vertex_buffer.id(), std::move(vertex_format), vertex_offset, vertex_count,
+      bounding_box_min, bounding_box_max));
+}
+
+Material::Material(Session* session) : Resource(session) {
+  session->Enqueue(NewCreateMaterialCmd(id()));
+}
+
+Material::Material(Material&& moved) : Resource(std::move(moved)) {}
+
+Material::~Material() = default;
+
+void Material::SetTexture(uint32_t image_id) {
+  session()->Enqueue(NewSetTextureCmd(id(), image_id));
+}
+
+void Material::SetColor(uint8_t red, uint8_t green, uint8_t blue,
+                        uint8_t alpha) {
+  session()->Enqueue(NewSetColorCmd(id(), red, green, blue, alpha));
+}
+
+Node::Node(Session* session) : Resource(session) {}
+
+Node::Node(Node&& moved) : Resource(std::move(moved)) {}
+
+Node::~Node() = default;
+
+void Node::SetTranslation(const float translation[3]) {
+  session()->Enqueue(NewSetTranslationCmd(id(), translation));
+}
+
+void Node::SetTranslation(uint32_t variable_id) {
+  session()->Enqueue(NewSetTranslationCmd(id(), variable_id));
+}
+
+void Node::SetScale(const float scale[3]) {
+  session()->Enqueue(NewSetScaleCmd(id(), scale));
+}
+
+void Node::SetScale(uint32_t variable_id) {
+  session()->Enqueue(NewSetScaleCmd(id(), variable_id));
+}
+
+void Node::SetRotation(const float quaternion[4]) {
+  session()->Enqueue(NewSetRotationCmd(id(), quaternion));
+}
+
+void Node::SetRotation(uint32_t variable_id) {
+  session()->Enqueue(NewSetRotationCmd(id(), variable_id));
+}
+
+void Node::SetAnchor(const float anchor[3]) {
+  session()->Enqueue(NewSetAnchorCmd(id(), anchor));
+}
+
+void Node::SetAnchor(uint32_t variable_id) {
+  session()->Enqueue(NewSetAnchorCmd(id(), variable_id));
+}
+
+void Node::SendSizeChangeHint(float width_change_factor,
+                              float height_change_factor) {
+  session()->Enqueue(NewSendSizeChangeHintCmdHACK(id(), width_change_factor,
+                                                  height_change_factor));
+}
+
+void Node::SetTag(uint32_t tag_value) {
+  session()->Enqueue(NewSetTagCmd(id(), tag_value));
+}
+
+void Node::SetHitTestBehavior(
+    fuchsia::ui::gfx::HitTestBehavior hit_test_behavior) {
+  session()->Enqueue(NewSetHitTestBehaviorCmd(id(), hit_test_behavior));
+}
+
+void Node::Detach() { session()->Enqueue(NewDetachCmd(id())); }
+
+ShapeNode::ShapeNode(Session* session) : Node(session) {
+  session->Enqueue(NewCreateShapeNodeCmd(id()));
+}
+
+ShapeNode::ShapeNode(ShapeNode&& moved) : Node(std::move(moved)) {}
+
+ShapeNode::~ShapeNode() = default;
+
+void ShapeNode::SetShape(uint32_t shape_id) {
+  session()->Enqueue(NewSetShapeCmd(id(), shape_id));
+}
+
+void ShapeNode::SetMaterial(uint32_t material_id) {
+  session()->Enqueue(NewSetMaterialCmd(id(), material_id));
+}
+
+ContainerNode::ContainerNode(Session* session) : Node(session) {}
+
+ContainerNode::ContainerNode(ContainerNode&& moved) : Node(std::move(moved)) {}
+
+ContainerNode::~ContainerNode() = default;
+
+void ContainerNode::AddChild(uint32_t child_node_id) {
+  session()->Enqueue(NewAddChildCmd(id(), child_node_id));
+}
+
+void ContainerNode::AddPart(uint32_t part_node_id) {
+  session()->Enqueue(NewAddPartCmd(id(), part_node_id));
+}
+
+void ContainerNode::DetachChildren() {
+  session()->Enqueue(NewDetachChildrenCmd(id()));
+}
+
+EntityNode::EntityNode(Session* session) : ContainerNode(session) {
+  session->Enqueue(NewCreateEntityNodeCmd(id()));
+}
+
+void EntityNode::Attach(const ViewHolder& view_holder) {
+  session()->Enqueue(NewAddChildCmd(id(), view_holder.id()));
+}
+
+void EntityNode::Snapshot(fuchsia::ui::gfx::SnapshotCallbackHACKPtr callback) {
+  session()->Enqueue(NewTakeSnapshotCmdHACK(id(), std::move(callback)));
+}
+
+EntityNode::~EntityNode() = default;
+
+void EntityNode::SetClip(uint32_t clip_id, bool clip_to_self) {
+  session()->Enqueue(NewSetClipCmd(id(), clip_id, clip_to_self));
+}
+
+ImportNode::ImportNode(Session* session) : ContainerNode(session) {}
+
+ImportNode::ImportNode(ImportNode&& moved) : ContainerNode(std::move(moved)) {}
+
+ImportNode::~ImportNode() {
+  ZX_DEBUG_ASSERT_MSG(is_bound_, "Import was never bound.");
+}
+
+void ImportNode::Bind(zx::eventpair import_token) {
+  ZX_DEBUG_ASSERT(!is_bound_);
+  session()->Enqueue(NewImportResourceCmd(
+      id(), fuchsia::ui::gfx::ImportSpec::NODE, std::move(import_token)));
+  is_bound_ = true;
+}
+
+void ImportNode::BindAsRequest(zx::eventpair* out_export_token) {
+  ZX_DEBUG_ASSERT(!is_bound_);
+  session()->Enqueue(NewImportResourceCmdAsRequest(
+      id(), fuchsia::ui::gfx::ImportSpec::NODE, out_export_token));
+  is_bound_ = true;
+}
+
+ViewHolder::ViewHolder(Session* session, zx::eventpair token,
+                       const std::string& debug_name)
+    : Resource(session) {
+  session->Enqueue(NewCreateViewHolderCmd(id(), std::move(token), debug_name));
+}
+
+ViewHolder::~ViewHolder() = default;
+
+void ViewHolder::SetViewProperties(const float bounding_box_min[3],
+                                   const float bounding_box_max[3],
+                                   const float inset_from_min[3],
+                                   const float inset_from_max[3]) {
+  session()->Enqueue(NewSetViewPropertiesCmd(id(), bounding_box_min,
+                                             bounding_box_max, inset_from_min,
+                                             inset_from_max));
+}
+
+void ViewHolder::SetViewProperties(
+    const fuchsia::ui::gfx::ViewProperties& props) {
+  session()->Enqueue(NewSetViewPropertiesCmd(id(), props));
+}
+
+View::View(Session* session, zx::eventpair token, const std::string& debug_name)
+    : Resource(session) {
+  session->Enqueue(NewCreateViewCmd(id(), std::move(token), debug_name));
+}
+
+View::~View() = default;
+
+void View::AddChild(const Node& child) const {
+  ZX_DEBUG_ASSERT(session() == child.session());
+  session()->Enqueue(NewAddChildCmd(id(), child.id()));
+}
+
+void View::DetachChild(const Node& child) const {
+  ZX_DEBUG_ASSERT(session() == child.session());
+  session()->Enqueue(NewDetachCmd(child.id()));
+}
+
+ClipNode::ClipNode(Session* session) : ContainerNode(session) {
+  session->Enqueue(NewCreateClipNodeCmd(id()));
+}
+
+ClipNode::ClipNode(ClipNode&& moved) : ContainerNode(std::move(moved)) {}
+
+ClipNode::~ClipNode() = default;
+
+OpacityNode::OpacityNode(Session* session) : ContainerNode(session) {
+  session->Enqueue(NewCreateOpacityNodeCmd(id()));
+}
+
+OpacityNode::OpacityNode(OpacityNode&& moved)
+    : ContainerNode(std::move(moved)) {}
+
+OpacityNode::~OpacityNode() = default;
+
+void OpacityNode::SetOpacity(float opacity) {
+  opacity = clamp(opacity, 0.f, 1.f);
+  session()->Enqueue(NewSetOpacityCmd(id(), opacity));
+}
+
+Variable::Variable(Session* session, fuchsia::ui::gfx::Value initial_value)
+    : Resource(session) {
+  session->Enqueue(NewCreateVariableCmd(id(), std::move(initial_value)));
+}
+
+Variable::Variable(Variable&& moved) : Resource(std::move(moved)) {}
+
+Variable::~Variable() = default;
+
+Scene::Scene(Session* session) : ContainerNode(session) {
+  session->Enqueue(NewCreateSceneCmd(id()));
+}
+
+Scene::Scene(Scene&& moved) : ContainerNode(std::move(moved)) {}
+
+Scene::~Scene() = default;
+
+void Scene::AddLight(uint32_t light_id) {
+  session()->Enqueue(NewAddLightCmd(id(), light_id));
+}
+
+void Scene::DetachLights() { session()->Enqueue(NewDetachLightsCmd(id())); }
+
+void CameraBase::SetTransform(const float eye_position[3],
+                              const float eye_look_at[3],
+                              const float eye_up[3]) {
+  session()->Enqueue(
+      NewSetCameraTransformCmd(id(), eye_position, eye_look_at, eye_up));
+}
+
+void CameraBase::SetPoseBuffer(const Buffer& buffer, uint32_t num_entries,
+                               int64_t base_time, uint64_t time_interval) {
+  session()->Enqueue(NewSetCameraPoseBufferCmd(id(), buffer.id(), num_entries,
+                                               base_time, time_interval));
+}
+
+Camera::Camera(const Scene& scene) : Camera(scene.session(), scene.id()) {}
+
+Camera::Camera(Session* session, uint32_t scene_id) : CameraBase(session) {
+  session->Enqueue(NewCreateCameraCmd(id(), scene_id));
+}
+
+Camera::Camera(Camera&& moved) : CameraBase(std::move(moved)) {}
+
+Camera::~Camera() = default;
+
+void Camera::SetProjection(const float fovy) {
+  session()->Enqueue(NewSetCameraProjectionCmd(id(), fovy));
+}
+
+StereoCamera::StereoCamera(const Scene& scene)
+    : StereoCamera(scene.session(), scene.id()) {}
+
+StereoCamera::StereoCamera(Session* session, uint32_t scene_id)
+    : CameraBase(session) {
+  session->Enqueue(NewCreateStereoCameraCmd(id(), scene_id));
+}
+
+StereoCamera::StereoCamera(StereoCamera&& moved)
+    : CameraBase(std::move(moved)) {}
+
+StereoCamera::~StereoCamera() = default;
+
+void StereoCamera::SetStereoProjection(const float left_projection[16],
+                                       const float right_projection[16]) {
+  session()->Enqueue(
+      NewSetStereoCameraProjectionCmd(id(), left_projection, right_projection));
+}
+
+Renderer::Renderer(Session* session) : Resource(session) {
+  session->Enqueue(NewCreateRendererCmd(id()));
+}
+
+Renderer::Renderer(Renderer&& moved) : Resource(std::move(moved)) {}
+
+Renderer::~Renderer() = default;
+
+void Renderer::SetCamera(uint32_t camera_id) {
+  session()->Enqueue(NewSetCameraCmd(id(), camera_id));
+}
+
+void Renderer::SetParam(fuchsia::ui::gfx::RendererParam param) {
+  session()->Enqueue(NewSetRendererParamCmd(id(), std::move(param)));
+}
+
+void Renderer::SetShadowTechnique(fuchsia::ui::gfx::ShadowTechnique technique) {
+  auto param = fuchsia::ui::gfx::RendererParam();
+  param.set_shadow_technique(technique);
+  SetParam(std::move(param));
+}
+
+void Renderer::SetDisableClipping(bool disable_clipping) {
+  session()->Enqueue(NewSetDisableClippingCmd(id(), disable_clipping));
+}
+
+Layer::Layer(Session* session) : Resource(session) {
+  session->Enqueue(NewCreateLayerCmd(id()));
+}
+
+Layer::Layer(Layer&& moved) : Resource(std::move(moved)) {}
+
+Layer::~Layer() = default;
+
+void Layer::SetRenderer(uint32_t renderer_id) {
+  session()->Enqueue(NewSetRendererCmd(id(), renderer_id));
+}
+
+void Layer::SetSize(const float size[2]) {
+  session()->Enqueue(NewSetSizeCmd(id(), size));
+}
+
+LayerStack::LayerStack(Session* session) : Resource(session) {
+  session->Enqueue(NewCreateLayerStackCmd(id()));
+}
+
+LayerStack::LayerStack(LayerStack&& moved) : Resource(std::move(moved)) {}
+
+LayerStack::~LayerStack() = default;
+
+void LayerStack::AddLayer(uint32_t layer_id) {
+  session()->Enqueue(NewAddLayerCmd(id(), layer_id));
+}
+
+void LayerStack::RemoveLayer(uint32_t layer_id) {
+  session()->Enqueue(NewRemoveLayerCmd(id(), layer_id));
+}
+
+void LayerStack::RemoveAllLayers() {
+  session()->Enqueue(NewRemoveAllLayersCmd(id()));
+}
+
+DisplayCompositor::DisplayCompositor(Session* session) : Resource(session) {
+  session->Enqueue(NewCreateDisplayCompositorCmd(id()));
+}
+
+DisplayCompositor::DisplayCompositor(DisplayCompositor&& moved)
+    : Resource(std::move(moved)) {}
+
+DisplayCompositor::~DisplayCompositor() = default;
+
+void DisplayCompositor::SetLayerStack(uint32_t layer_stack_id) {
+  session()->Enqueue(NewSetLayerStackCmd(id(), layer_stack_id));
+}
+
+Compositor::Compositor(Session* session) : Resource(session) {
+  session->Enqueue(NewCreateCompositorCmd(id()));
+}
+
+Compositor::Compositor(Compositor&& moved) : Resource(std::move(moved)) {}
+
+Compositor::~Compositor() = default;
+
+void Compositor::SetLayerStack(uint32_t layer_stack_id) {
+  session()->Enqueue(NewSetLayerStackCmd(id(), layer_stack_id));
+}
+
+Light::Light(Session* session) : Resource(session) {}
+
+Light::Light(Light&& moved) : Resource(std::move(moved)) {}
+
+Light::~Light() = default;
+
+void Light::SetColor(const float rgb[3]) {
+  session()->Enqueue(NewSetLightColorCmd(id(), rgb));
+}
+
+void Light::SetColor(uint32_t variable_id) {
+  session()->Enqueue(NewSetLightColorCmd(id(), variable_id));
+}
+
+void Light::Detach() { session()->Enqueue(NewDetachLightCmd(id())); }
+
+AmbientLight::AmbientLight(Session* session) : Light(session) {
+  session->Enqueue(NewCreateAmbientLightCmd(id()));
+}
+
+AmbientLight::AmbientLight(AmbientLight&& moved) : Light(std::move(moved)) {}
+
+AmbientLight::~AmbientLight() = default;
+
+DirectionalLight::DirectionalLight(Session* session) : Light(session) {
+  session->Enqueue(NewCreateDirectionalLightCmd(id()));
+}
+
+DirectionalLight::DirectionalLight(DirectionalLight&& moved)
+    : Light(std::move(moved)) {}
+
+DirectionalLight::~DirectionalLight() = default;
+
+void DirectionalLight::SetDirection(const float direction[3]) {
+  session()->Enqueue(NewSetLightDirectionCmd(id(), direction));
+}
+
+void DirectionalLight::SetDirection(uint32_t variable_id) {
+  session()->Enqueue(NewSetLightDirectionCmd(id(), variable_id));
+}
+
+}  // namespace scenic
diff --git a/pkg/scenic_cpp/session.cc b/pkg/scenic_cpp/session.cc
new file mode 100644
index 0000000..7f48da9
--- /dev/null
+++ b/pkg/scenic_cpp/session.cc
@@ -0,0 +1,184 @@
+// Copyright 2017 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "lib/ui/scenic/cpp/session.h"
+
+#include <stdio.h>
+#include <zircon/assert.h>
+
+#include "lib/ui/scenic/cpp/commands.h"
+
+namespace scenic {
+
+constexpr size_t kCommandsPerMessage =
+    (ZX_CHANNEL_MAX_MSG_BYTES - sizeof(fidl_message_header_t) -
+     sizeof(fidl_vector_t)) /
+    sizeof(fuchsia::ui::scenic::Command);
+
+SessionPtrAndListenerRequest CreateScenicSessionPtrAndListenerRequest(
+    fuchsia::ui::scenic::Scenic* scenic) {
+  fuchsia::ui::scenic::SessionPtr session;
+  fidl::InterfaceHandle<fuchsia::ui::scenic::SessionListener> listener_handle;
+  auto listener_request = listener_handle.NewRequest();
+
+  scenic->CreateSession(session.NewRequest(), listener_handle.Bind());
+
+  return {std::move(session), std::move(listener_request)};
+}
+
+Session::Session(fuchsia::ui::scenic::SessionPtr session,
+                 fidl::InterfaceRequest<fuchsia::ui::scenic::SessionListener>
+                     session_listener)
+    : session_(std::move(session)), session_listener_binding_(this) {
+  ZX_DEBUG_ASSERT(session_);
+  if (session_listener.is_valid())
+    session_listener_binding_.Bind(std::move(session_listener));
+}
+
+Session::Session(fuchsia::ui::scenic::Scenic* scenic)
+    : session_listener_binding_(this) {
+  ZX_DEBUG_ASSERT(scenic);
+  scenic->CreateSession(session_.NewRequest(),
+                        session_listener_binding_.NewBinding());
+}
+
+Session::Session(SessionPtrAndListenerRequest session_and_listener)
+    : Session(std::move(session_and_listener.first),
+              std::move(session_and_listener.second)) {}
+
+Session::~Session() {
+  ZX_DEBUG_ASSERT_MSG(resource_count_ == 0,
+                      "Some resources outlived the session: %u",
+                      resource_count_);
+}
+
+uint32_t Session::AllocResourceId() {
+  uint32_t resource_id = next_resource_id_++;
+  ZX_DEBUG_ASSERT(resource_id);
+  resource_count_++;
+  return resource_id;
+}
+
+void Session::ReleaseResource(uint32_t resource_id) {
+  resource_count_--;
+  Enqueue(NewReleaseResourceCmd(resource_id));
+}
+
+void Session::Enqueue(fuchsia::ui::gfx::Command command) {
+  Enqueue(NewCommand(std::move(command)));
+}
+
+void Session::Enqueue(fuchsia::ui::input::Command command) {
+  Enqueue(NewCommand(std::move(command)));
+}
+
+void Session::Enqueue(fuchsia::ui::scenic::Command command) {
+  commands_.push_back(std::move(command));
+  if (commands_->size() >= kCommandsPerMessage ||
+      command.Which() == fuchsia::ui::scenic::Command::Tag::kInput) {
+    Flush();
+  }
+}
+
+void Session::EnqueueAcquireFence(zx::event fence) {
+  ZX_DEBUG_ASSERT(fence);
+  acquire_fences_.push_back(std::move(fence));
+}
+
+void Session::EnqueueReleaseFence(zx::event fence) {
+  ZX_DEBUG_ASSERT(fence);
+  release_fences_.push_back(std::move(fence));
+}
+
+void Session::Flush() {
+  ZX_DEBUG_ASSERT(session_);
+  if (!commands_->empty()) {
+    ZX_DEBUG_ASSERT(static_cast<bool>(commands_));
+    session_->Enqueue(std::move(commands_));
+
+    // After being moved, |commands_| is in a "valid but unspecified state";
+    // see http://en.cppreference.com/w/cpp/utility/move.  Calling reset() makes
+    // it safe to continue using.
+    commands_.reset();
+  }
+}
+
+void Session::Present(uint64_t presentation_time, PresentCallback callback) {
+  ZX_DEBUG_ASSERT(session_);
+  Flush();
+
+  if (acquire_fences_.is_null())
+    acquire_fences_.resize(0u);
+  if (release_fences_.is_null())
+    release_fences_.resize(0u);
+  session_->Present(presentation_time, std::move(acquire_fences_),
+                    std::move(release_fences_), std::move(callback));
+}
+
+void Session::HitTest(uint32_t node_id, const float ray_origin[3],
+                      const float ray_direction[3], HitTestCallback callback) {
+  ZX_DEBUG_ASSERT(session_);
+  fuchsia::ui::gfx::vec3 ray_origin_vec;
+  ray_origin_vec.x = ray_origin[0];
+  ray_origin_vec.y = ray_origin[1];
+  ray_origin_vec.z = ray_origin[2];
+
+  fuchsia::ui::gfx::vec3 ray_direction_vec;
+  ray_direction_vec.x = ray_direction[0];
+  ray_direction_vec.y = ray_direction[1];
+  ray_direction_vec.z = ray_direction[2];
+
+  session_->HitTest(node_id, std::move(ray_origin_vec),
+                    std::move(ray_direction_vec), std::move(callback));
+}
+
+void Session::HitTestDeviceRay(
+    const float ray_origin[3], const float ray_direction[3],
+    fuchsia::ui::scenic::Session::HitTestDeviceRayCallback callback) {
+  ZX_DEBUG_ASSERT(session_);
+  fuchsia::ui::gfx::vec3 ray_origin_vec;
+  ray_origin_vec.x = ray_origin[0];
+  ray_origin_vec.y = ray_origin[1];
+  ray_origin_vec.z = ray_origin[2];
+
+  fuchsia::ui::gfx::vec3 ray_direction_vec;
+  ray_direction_vec.x = ray_direction[0];
+  ray_direction_vec.y = ray_direction[1];
+  ray_direction_vec.z = ray_direction[2];
+
+  session_->HitTestDeviceRay(std::move(ray_origin_vec),
+                             std::move(ray_direction_vec), std::move(callback));
+}
+
+void Session::Unbind() {
+  ZX_DEBUG_ASSERT(session_);
+  ZX_DEBUG_ASSERT(!session_handle_);
+  session_handle_ = session_.Unbind();
+  session_ = nullptr;
+}
+
+void Session::Rebind() {
+  ZX_DEBUG_ASSERT(!session_);
+  ZX_DEBUG_ASSERT(session_handle_);
+  session_ = fuchsia::ui::scenic::SessionPtr(session_handle_.Bind());
+  session_handle_ = nullptr;
+}
+
+void Session::OnScenicError(fidl::StringPtr error) {
+  // TODO(SCN-903): replace fprintf with SDK-approved logging mechanism.  Also
+  // remove "#include <stdio.h>".
+  fprintf(stderr, "Session error: %s", error->c_str());
+}
+
+void Session::OnScenicEvent(
+    fidl::VectorPtr<fuchsia::ui::scenic::Event> events) {
+  if (event_handler_)
+    event_handler_(std::move(events));
+}
+
+void Session::SetDebugName(const std::string& debug_name) {
+  session_->SetDebugName(debug_name);
+}
+
+}  // namespace scenic
diff --git a/pkg/svc/include/lib/svc/dir.h b/pkg/svc/include/lib/svc/dir.h
new file mode 100644
index 0000000..8e16c97
--- /dev/null
+++ b/pkg/svc/include/lib/svc/dir.h
@@ -0,0 +1,61 @@
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef LIB_SVC_SVC_H_
+#define LIB_SVC_SVC_H_
+
+#include <lib/async/dispatcher.h>
+#include <zircon/compiler.h>
+#include <zircon/types.h>
+
+__BEGIN_CDECLS
+
+typedef void(svc_connector_t)(void* context, const char* service_name,
+                              zx_handle_t service_request);
+
+typedef struct svc_dir svc_dir_t;
+
+__EXPORT zx_status_t svc_dir_create(async_dispatcher_t* dispatcher,
+                                    zx_handle_t directory_request,
+                                    svc_dir_t** out_result);
+
+// Adds a service named |service_name| to the given |dir|.
+//
+// If |type| is non-NULL, the service will be published in a directory whose
+// name matches the |type|. If |type| is NULL, the service will be published in
+// the root directory.
+//
+// The most commonly used values for |type| are "public", "debug", and "ctrl".
+// Services published under "public" are made available to clients via
+// |fuchsia.sys.Lancher#CreateComponent|. The "debug" serivices are exposed via
+// the hub. The "ctrl" services are used by the core platform to communicate
+// with your program.
+//
+// When a client requests the service, |handler| will be called on the async_t
+// passed to |svc_dir_create|. The |context| will be passed to |handler| as its
+// first argument.
+//
+// This may fail in two ways. If an entry with the given
+// |service_name| already exists, this returns
+// ZX_ERR_ALREADY_EXISTS. If the provided |service_name| is invalid,
+// ZX_ERR_INVALID_ARGS is returned. Otherwise, this returns ZX_OK.
+__EXPORT zx_status_t svc_dir_add_service(svc_dir_t* dir, const char* type,
+                                         const char* service_name,
+                                         void* context,
+                                         svc_connector_t* handler);
+
+// Removes the service named |service_name| of type |type| from the
+// given |dir|. This reports a failure if the entry does not exist, by
+// returning ZX_ERR_NOT_FOUND. Otherwise, the service entry is
+// removed, and ZX_OK is returned.
+__EXPORT zx_status_t svc_dir_remove_service(svc_dir_t* dir, const char* type,
+                                            const char* service_name);
+
+// Destroy the provided directory. This currently cannot fail, and
+// returns ZX_OK.
+__EXPORT zx_status_t svc_dir_destroy(svc_dir_t* dir);
+
+__END_CDECLS
+
+#endif  // LIB_SVC_SVC_H_
diff --git a/pkg/svc/meta.json b/pkg/svc/meta.json
new file mode 100644
index 0000000..2a183d5
--- /dev/null
+++ b/pkg/svc/meta.json
@@ -0,0 +1,27 @@
+{
+  "binaries": {
+    "arm64": {
+      "debug": ".build-id/28/16547647b2a89d.debug", 
+      "dist": "arch/arm64/dist/libsvc.so", 
+      "link": "arch/arm64/lib/libsvc.so"
+    }, 
+    "x64": {
+      "debug": ".build-id/31/f3907157249ab0.debug", 
+      "dist": "arch/x64/dist/libsvc.so", 
+      "link": "arch/x64/lib/libsvc.so"
+    }
+  }, 
+  "deps": [
+    "async", 
+    "fdio", 
+    "trace-engine"
+  ], 
+  "format": "shared", 
+  "headers": [
+    "pkg/svc/include/lib/svc/dir.h"
+  ], 
+  "include_dir": "pkg/svc/include", 
+  "name": "svc", 
+  "root": "pkg/svc", 
+  "type": "cc_prebuilt_library"
+}
\ No newline at end of file
diff --git a/pkg/sync/include/lib/sync/completion.h b/pkg/sync/include/lib/sync/completion.h
new file mode 100644
index 0000000..515a563
--- /dev/null
+++ b/pkg/sync/include/lib/sync/completion.h
@@ -0,0 +1,55 @@
+// Copyright 2016 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef LIB_SYNC_COMPLETION_H_
+#define LIB_SYNC_COMPLETION_H_
+
+#include <zircon/compiler.h>
+#include <zircon/types.h>
+
+__BEGIN_CDECLS
+
+typedef struct sync_completion {
+    zx_futex_t futex;
+
+#ifdef __cplusplus
+    sync_completion()
+        : futex(0) {}
+#endif
+} sync_completion_t;
+
+#if !defined(__cplusplus)
+#define SYNC_COMPLETION_INIT ((sync_completion_t){0})
+#endif
+
+// Returns ZX_ERR_TIMED_OUT if timeout elapses, and ZX_OK if woken by
+// a call to sync_completion_signal or if the completion has already been
+// signaled.
+zx_status_t sync_completion_wait(sync_completion_t* completion, zx_duration_t timeout);
+
+// Returns ZX_ERR_TIMED_OUT if deadline elapses, and ZX_OK if woken by
+// a call to sync_completion_signal or if the completion has already been
+// signaled.
+zx_status_t sync_completion_wait_deadline(sync_completion_t* completion, zx_time_t deadline);
+
+// Awakens all waiters on the completion, and marks it as
+// signaled. Waits after this call but before a reset of the
+// completion will also see the signal and immediately return.
+void sync_completion_signal(sync_completion_t* completion);
+
+// Marks the completion as signaled, but doesn't awaken all waiters
+// right away. Instead, all waiters are requeued to the |futex|.
+// Waits after this call but before a reset of the
+// completion will also see the signal and immediately return.
+//
+// Intended to be used by libsync internally, e.g. the condition variable
+// implementation.
+void sync_completion_signal_requeue(sync_completion_t* completion, zx_futex_t* futex);
+
+// Resets the completion's signaled state to unsignaled.
+void sync_completion_reset(sync_completion_t* completion);
+
+__END_CDECLS
+
+#endif // LIB_SYNC_COMPLETION_H_
diff --git a/pkg/sync/include/lib/sync/condition.h b/pkg/sync/include/lib/sync/condition.h
new file mode 100644
index 0000000..6f6eb58
--- /dev/null
+++ b/pkg/sync/include/lib/sync/condition.h
@@ -0,0 +1,95 @@
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef LIB_SYNC_CONDITION_H_
+#define LIB_SYNC_CONDITION_H_
+
+#include <lib/sync/mutex.h>
+#include <zircon/compiler.h>
+#include <zircon/types.h>
+
+__BEGIN_CDECLS
+
+// A condition variable that works with a sync_mutex_t
+typedef struct sync_condition {
+    int lock;
+    void* head;
+    void* tail;
+
+#ifdef __cplusplus
+    sync_condition()
+        : lock(0), head(nullptr), tail(nullptr) {}
+#endif
+} sync_condition_t;
+
+#if !defined(__cplusplus)
+#define SYNC_CONDITION_INIT ((sync_condition_t){0})
+#endif
+
+// Block until |condition| is signaled by sync_condition_signal()/sync_condition_broadcast(), or a spurious
+// wake up occurs.
+//
+// |mutex| must be in a locked state, and will be atomically unlocked for the duration of the wait,
+// then locked again before the function returns.
+void sync_condition_wait(sync_condition_t* condition, sync_mutex_t* mutex);
+
+// Block until |condition| is signaled by sync_condition_signal()/sync_condition_broadcast(), or a spurious
+// wake up or a timeout occurs.
+//
+// |mutex| must be in a locked state, and will be atomically unlocked for the duration of the wait,
+// then locked again before the function returns.
+//
+// ZX_TIME_INFINITE can be used for |deadline| to wait for an unlimited amount of time.
+//
+// Return value:
+//      ZX_OK if |condition| was signaled or a spurious wake up occurred.
+//      ZX_ERR_TIMED_OUT if the wait timed out.
+zx_status_t sync_condition_timedwait(sync_condition_t* condition, sync_mutex_t* mutex, zx_time_t deadline);
+
+// Wake up one thread waiting for |condition|.
+//
+// If the woken thread was waiting on sync_condition_timedwait(), then it is guaranteed
+// to receive a ZX_OK return value even if a race with a timeout occurs. As an example
+// where this makes a difference, consider the following implementation of a multi-producer,
+// multi-consumer queue:
+//
+// Message* MessageQueue::DequeueTimeout(zx_time_t deadline) {
+//    sync_mutex_lock(&mutex_);
+//    for (;;) {
+//        if (!list_.empty()) {
+//            Message* msg = list_.front();
+//            list_.pop_front();
+//            sync_mutex_unlock(&mutex_);
+//            return msg;
+//        }
+//        zx_status_t status = sync_condition_timedwait(&condition_, &mutex_, deadline);
+//        if (status == ZX_ERR_TIMED_OUT) {
+//            // Without the above guarantee, this would be a bug: a race between
+//            // a timeout and a signal() would result in a missed wakeup.
+//            // To fix that, we would need to recheck list_.empty() here, which
+//            // is not obvious and would make the code more complex.
+//            sync_mutex_unlock(&mutex_);
+//            return nullptr;
+//        }
+//    }
+// }
+//
+// void MessageQueue::Enqueue(Message* msg) {
+//     sync_mutex_lock(&mutex_);
+//     list_.push_back(msg);
+//     // Signal just one waiter. Assumes that any possible waiter will dequeue the message.
+//     sync_condition_signal(&condvar_);
+//     sync_mutex_unlock(&mutex_);
+// }
+//
+// Note that pthread does not seem to require this property, and in fact the current upstream
+// implementation of pthread_cond_timedwait() in MUSL does not have it.
+void sync_condition_signal(sync_condition_t* condition);
+
+// Wake up all threads that are currently waiting for |condition|.
+void sync_condition_broadcast(sync_condition_t* condition);
+
+__END_CDECLS
+
+#endif // LIB_SYNC_CONDITION_H_
diff --git a/pkg/sync/include/lib/sync/internal/condition-template.h b/pkg/sync/include/lib/sync/internal/condition-template.h
new file mode 100644
index 0000000..7bd4f2d
--- /dev/null
+++ b/pkg/sync/include/lib/sync/internal/condition-template.h
@@ -0,0 +1,296 @@
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef LIB_SYNC_INTERNAL_CONDITION_TEMPLATE_H_
+#define LIB_SYNC_INTERNAL_CONDITION_TEMPLATE_H_
+
+#include <zircon/syscalls.h>
+#include <lib/sync/completion.h>
+#include <lib/sync/mutex.h>
+
+namespace condition_impl_internal {
+
+// A template implementation of a condition variable.
+// The algorithm is borrowed from MUSL.
+//
+// The 'Condition' struct must contain the following fields:
+//      int lock;
+//      void* head;
+//      void* tail;
+//
+// The following struct template must be specialized for the mutex type 'Mutex'
+// in order to instantiate the template:
+template <typename Mutex>
+struct MutexOps {
+    // Return a pointer to the futex that backs the |mutex|
+    static zx_futex_t* get_futex(Mutex* mutex);
+
+    // Lock the |mutex|. If an error occurs while locking the mutex,
+    // ZX_ERR_BAD_STATE must be returned. An implementation-defined
+    // error code can be returned via |mutex_lock_err| if it's not null.
+    static zx_status_t lock(Mutex* mutex, int* mutex_lock_err);
+
+    // Similar to lock(), but also update the waiter information in the mutex.
+    // If the mutex implements waiter counting, then the count must be adjusted
+    // by |waiters_delta|. Otherwise, the mutex must be marked as potentially
+    // having waiters.
+    static zx_status_t lock_with_waiters(
+        Mutex* mutex, int waiters_delta, int* mutex_lock_err);
+
+    // Unlock the mutex
+    static void unlock(Mutex* mutex);
+};
+
+// Note that this library is used by libc, and as such needs to use
+// '_zx_' function names for syscalls and not the regular 'zx_' names.
+
+static inline void spin() {
+#if defined(__x86_64__)
+    __asm__ __volatile__("pause"
+                         :
+                         :
+                         : "memory");
+#elif defined(__aarch64__)
+    __atomic_thread_fence(__ATOMIC_SEQ_CST);
+#else
+#error Please define spin() for your architecture
+#endif
+}
+
+static inline bool cas(int* ptr, int* expected, int desired) {
+    return __atomic_compare_exchange_n(ptr, expected, desired, false,
+                                       __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST);
+}
+
+static inline void wait(int* futex, int current_value) {
+    int spins = 100;
+    while (spins--) {
+        if (__atomic_load_n(futex, __ATOMIC_SEQ_CST) == current_value) {
+            spin();
+        } else {
+            return;
+        }
+    }
+    while (__atomic_load_n(futex, __ATOMIC_SEQ_CST) == current_value) {
+        _zx_futex_wait(futex, current_value, ZX_HANDLE_INVALID, ZX_TIME_INFINITE);
+    }
+}
+
+enum {
+    WAITING,
+    SIGNALED,
+    LEAVING,
+};
+
+struct Waiter {
+    Waiter* prev = nullptr;
+    Waiter* next = nullptr;
+    int state = WAITING;
+    sync_completion_t ready;
+    int* notify = nullptr;
+};
+
+// Return value:
+//      - ZX_OK if the condition variable was signaled;
+//      - ZX_ERR_TIMED_OUT if deadline was reached;
+//      - ZX_ERR_BAD_STATE if there was an error locking the mutex.
+//        In this case, |mutex_lock_err|, if not null, will be populated with an error code
+//        provided by the mutex implementation.
+template <typename Condition, typename Mutex>
+static inline zx_status_t timedwait(Condition* c, Mutex* mutex, zx_time_t deadline,
+                                    int* mutex_lock_err)
+    __TA_NO_THREAD_SAFETY_ANALYSIS {
+    sync_mutex_lock(reinterpret_cast<sync_mutex_t*>(&c->lock));
+
+    Waiter node;
+
+    // Add our waiter node onto the condition's list.  We add the node to the
+    // head of the list, but this is logically the end of the queue.
+    node.next = static_cast<Waiter*>(c->head);
+    c->head = &node;
+    if (!c->tail) {
+        c->tail = &node;
+    } else {
+        node.next->prev = &node;
+    }
+
+    sync_mutex_unlock(reinterpret_cast<sync_mutex_t*>(&c->lock));
+
+    MutexOps<Mutex>::unlock(mutex);
+
+    // Wait to be signaled.  There are multiple ways this wait could finish:
+    //  1) After being woken by signal().
+    //  2) After being woken by a mutex unlock, after we were
+    //     requeued from the condition's futex to the mutex's futex (by
+    //     timedwait() in another thread).
+    //  3) After a timeout.
+    // In the original Linux version of this algorithm, this could also exit
+    // when interrupted by an asynchronous signal, but that does not apply on Zircon.
+    sync_completion_wait_deadline(&node.ready, deadline);
+
+    int oldstate = WAITING;
+    if (cas(&node.state, &oldstate, LEAVING)) {
+        // The wait timed out.  So far, this thread was not signaled by
+        // signal() -- this thread was able to move state.node out of the
+        // WAITING state before any signal() call could do that.
+        //
+        // This thread must therefore remove the waiter node from the
+        // list itself.
+
+        // Access to cv object is valid because this waiter was not
+        // yet signaled and a new signal/broadcast cannot return
+        // after seeing a LEAVING waiter without getting notified
+        // via the futex notify below.
+
+        sync_mutex_lock(reinterpret_cast<sync_mutex_t*>(&c->lock));
+
+        // Remove our waiter node from the list.
+        if (c->head == &node) {
+            c->head = node.next;
+        } else if (node.prev) {
+            node.prev->next = node.next;
+        }
+
+        if (c->tail == &node) {
+            c->tail = node.prev;
+        } else if (node.next) {
+            node.next->prev = node.prev;
+        }
+
+        sync_mutex_unlock(reinterpret_cast<sync_mutex_t*>(&c->lock));
+
+        // It is possible that signal() saw our waiter node after we set
+        // node.state to LEAVING but before we removed the node from the
+        // list.  If so, it will have set node.notify and will be waiting
+        // on it, and we need to wake it up.
+        //
+        // This is rather complex.  An alternative would be to eliminate
+        // the |node.state| field and always claim |lock| if we could have
+        // got a timeout.  However, that presumably has higher overhead
+        // (since it contends |lock| and involves more atomic ops).
+        if (node.notify) {
+            if (__atomic_fetch_add(node.notify, -1, __ATOMIC_SEQ_CST) == 1) {
+                _zx_futex_wake(node.notify, 1);
+            }
+        }
+
+        // We don't need lock_with_waiters() here: we haven't been signaled, and will
+        // never be since we managed to claim the state as LEAVING. This means that
+        // we could not have been woken up by unlock_requeue() + mutex unlock().
+        if (MutexOps<Mutex>::lock(mutex, mutex_lock_err) != ZX_OK) {
+            return ZX_ERR_BAD_STATE;
+        }
+        return ZX_ERR_TIMED_OUT;
+    }
+
+    // Since the CAS above failed, we have been signaled.
+    // It could still be the case that sync_completion_wait_deadline() above timed out,
+    // so we need to make sure to wait for the completion to control the wake order.
+    // If the completion has already been signaled, this will return immediately.
+    sync_completion_wait_deadline(&node.ready, ZX_TIME_INFINITE);
+
+    // By this point, our part of the waiter list cannot change further.
+    // It has been unlinked from the condition by signal().
+    // Any timed out waiters would have removed themselves from the list
+    // before signal() signaled the first node.ready in our list.
+    //
+    // It is therefore safe now to read node.next and node.prev without
+    // holding c->lock.
+
+    // As an optimization, we only update waiter count at the beginning and
+    // end of the signaled list.
+    int waiters_delta = 0;
+    if (!node.prev) {
+        waiters_delta++;
+    }
+    if (!node.next) {
+        waiters_delta--;
+    }
+
+    // We must leave the mutex in the "locked with waiters" state here
+    // (or adjust its waiter count, depending on the implementation).
+    // There are two reasons for that:
+    //  1) If we do the unlock_requeue() below, a condition waiter will be
+    //     requeued to the mutex's futex.  We need to ensure that it will
+    //     be signaled by mutex unlock() in future.
+    //  2) If the current thread was woken via an unlock_requeue() +
+    //     mutex unlock, there *might* be another thread waiting for
+    //     the mutex after us in the queue.  We need to ensure that it
+    //     will be signaled by zxr_mutex_unlock() in future.
+    zx_status_t status = MutexOps<Mutex>::lock_with_waiters(mutex, waiters_delta, mutex_lock_err);
+
+    if (node.prev) {
+        // Signal the completion that's holding back the next waiter, and
+        // requeue it to the mutex so that it will be woken when the
+        // mutex is unlocked.
+        sync_completion_signal_requeue(&node.prev->ready, MutexOps<Mutex>::get_futex(mutex));
+    }
+
+    // Even if the first call to sync_completion_wait_deadline() timed out,
+    // we still have been signaled. Thus we still return ZX_OK rather than
+    // ZX_ERR_TIMED_OUT. This provides the following guarantee: if multiple
+    // threads are waiting when signal() is called, at least one waiting
+    // thread will be woken *and* get a ZX_OK from timedwait() (unless there
+    // is an error locking the mutex). This property does not appear to be
+    // required by pthread condvars, although an analogous property is
+    // required for futex wake-ups. We also require this property for
+    // sync_condition_t.
+    return status;
+}
+
+// This will wake up to |n| threads that are waiting on the condition,
+// or all waiting threads if |n| is set to -1
+template <typename Condition>
+static inline void signal(Condition* c, int n) {
+    Waiter* p;
+    Waiter* first = nullptr;
+    int ref = 0;
+    int cur;
+
+    sync_mutex_lock(reinterpret_cast<sync_mutex_t*>(&c->lock));
+    for (p = static_cast<Waiter*>(c->tail); n && p; p = p->prev) {
+        int oldstate = WAITING;
+        if (!cas(&p->state, &oldstate, SIGNALED)) {
+            // This waiter timed out, and it marked itself as in the
+            // LEAVING state.  However, it hasn't yet claimed |lock|
+            // (since we claimed the lock first) and so it hasn't yet
+            // removed itself from the list.  We will wait for the waiter
+            // to remove itself from the list and to notify us of that.
+            __atomic_fetch_add(&ref, 1, __ATOMIC_SEQ_CST);
+            p->notify = &ref;
+        } else {
+            n--;
+            if (!first) {
+                first = p;
+            }
+        }
+    }
+    // Split the list, leaving any remainder on the cv.
+    if (p) {
+        if (p->next) {
+            p->next->prev = 0;
+        }
+        p->next = 0;
+    } else {
+        c->head = 0;
+    }
+    c->tail = p;
+    sync_mutex_unlock(reinterpret_cast<sync_mutex_t*>(&c->lock));
+
+    // Wait for any waiters in the LEAVING state to remove
+    // themselves from the list before returning or allowing
+    // signaled threads to proceed.
+    while ((cur = __atomic_load_n(&ref, __ATOMIC_SEQ_CST))) {
+        wait(&ref, cur);
+    }
+
+    // Allow first signaled waiter, if any, to proceed.
+    if (first) {
+        sync_completion_signal(&first->ready);
+    }
+}
+
+} // namespace condition_impl_internal
+
+#endif // LIB_SYNC_INTERNAL_CONDITION_TEMPLATE_H_
diff --git a/pkg/sync/include/lib/sync/mutex.h b/pkg/sync/include/lib/sync/mutex.h
new file mode 100644
index 0000000..37a5cd3
--- /dev/null
+++ b/pkg/sync/include/lib/sync/mutex.h
@@ -0,0 +1,72 @@
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef LIB_SYNC_MUTEX_H_
+#define LIB_SYNC_MUTEX_H_
+
+#include <zircon/compiler.h>
+#include <zircon/types.h>
+
+__BEGIN_CDECLS
+
+// An optimal, non-recursive mutex on Fuchsia.
+//
+// The |mutex_t| mutex in the standard library has several quirks in its design
+// that prevent it from being optimal. For example, the |mutex_t| interface
+// supports recursion, which adds a branch to |mutex_init| to check that the
+// client has not asked for recusion, and |mutex_timedlock| operates in
+// |struct timespec| rather than |zx_time_t|.
+//
+// |sync_mutex| resolves these issues.
+typedef struct __TA_CAPABILITY("mutex") sync_mutex {
+    zx_futex_t futex;
+
+#ifdef __cplusplus
+    sync_mutex()
+        : futex(0) {}
+#endif
+} sync_mutex_t;
+
+#if !defined(__cplusplus)
+#define SYNC_MUTEX_INIT ((sync_mutex_t){0})
+#endif
+
+// Locks the mutex.
+//
+// The current thread will block until the mutex is acquired. The mutex is
+// non-recursive, which means attempting to lock a mutex that is already held by
+// this thread will deadlock.
+void sync_mutex_lock(sync_mutex_t* mutex) __TA_ACQUIRE(mutex);
+
+// Locks the mutex and mark the mutex as having a waiter.
+//
+// Similar to |sync_mutex_lock| but markes the mutex as having a waiter. Intended
+// to be used by the condition variable implementation.
+void sync_mutex_lock_with_waiter(sync_mutex_t* mutex) __TA_ACQUIRE(mutex);
+
+// Attempt to lock the mutex until |deadline|.
+//
+// The current thread will block until either the mutex is acquired or
+// |deadline| passes.
+//
+// |deadline| is expressed as an absolute time in the ZX_CLOCK_MONOTONIC
+// timebase.
+//
+// Returns |ZX_OK| if the lock is acquired, and |ZX_ERR_TIMED_OUT| if the
+// deadline passes.
+zx_status_t sync_mutex_timedlock(sync_mutex_t* mutex, zx_time_t deadline);
+
+// Attempts to lock the mutex without blocking.
+//
+// Returns |ZX_OK| if the lock is obtained, and |ZX_ERR_BAD_STATE| if not.
+zx_status_t sync_mutex_trylock(sync_mutex_t* mutex);
+
+// Unlocks the mutex.
+//
+// Does nothing if the mutex is already unlocked.
+void sync_mutex_unlock(sync_mutex_t* mutex) __TA_RELEASE(mutex);
+
+__END_CDECLS
+
+#endif // LIB_SYNC_MUTEX_H_
diff --git a/pkg/sync/meta.json b/pkg/sync/meta.json
new file mode 100644
index 0000000..4908432
--- /dev/null
+++ b/pkg/sync/meta.json
@@ -0,0 +1,22 @@
+{
+  "binaries": {
+    "arm64": {
+      "link": "arch/arm64/lib/libsync.a"
+    }, 
+    "x64": {
+      "link": "arch/x64/lib/libsync.a"
+    }
+  }, 
+  "deps": [], 
+  "format": "static", 
+  "headers": [
+    "pkg/sync/include/lib/sync/completion.h", 
+    "pkg/sync/include/lib/sync/condition.h", 
+    "pkg/sync/include/lib/sync/internal/condition-template.h", 
+    "pkg/sync/include/lib/sync/mutex.h"
+  ], 
+  "include_dir": "pkg/sync/include", 
+  "name": "sync", 
+  "root": "pkg/sync", 
+  "type": "cc_prebuilt_library"
+}
\ No newline at end of file
diff --git a/pkg/syslog/include/lib/syslog/global.h b/pkg/syslog/include/lib/syslog/global.h
new file mode 100644
index 0000000..9c9cc89
--- /dev/null
+++ b/pkg/syslog/include/lib/syslog/global.h
@@ -0,0 +1,132 @@
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+//
+// Entry points used by clients.
+
+#ifndef LIB_SYSLOG_GLOBAL_H_
+#define LIB_SYSLOG_GLOBAL_H_
+
+#include <lib/syslog/logger.h>
+
+__BEGIN_CDECLS
+
+// Gets the global logger for the process to which log messages emitted
+// using the FX_LOG macros will be written.  Returns NULL if logging is
+// not configured.
+fx_logger_t* fx_log_get_logger(void);
+
+// Returns true if writing messages with the given severity is enabled in the
+// global logger.
+static inline bool fx_log_is_enabled(fx_log_severity_t severity) {
+    fx_logger_t* logger = fx_log_get_logger();
+    return logger && severity >= fx_logger_get_min_severity(logger);
+}
+
+// Initializes the logging infrastructure with the specified configuration.
+// Returns |ZX_ERR_BAD_STATE| if logging has already been initialized.
+// If |console_fd| and |log_service_channel| are invalid in |config|,
+// this function chooses a default destination for the log.
+// |config| can be safely deallocated after this function returns.
+//
+// global logger would be deallocated once program ends.
+zx_status_t fx_log_init_with_config(const fx_logger_config_t* config);
+
+// Initializes the logging infrastructure for this process using default
+// parameters. Returns |ZX_ERR_BAD_STATE| if logging has already been
+// initialized.
+//
+// global logger would be deallocated once program ends.
+zx_status_t fx_log_init(void);
+
+// Returns true if writing messages with the given severity is enabled in the
+// global logger. |severity| is one of DEBUG, INFO, WARNING, ERROR, or FATAL.
+#define FX_LOG_IS_ENABLED(severity) (fx_log_is_enabled(FX_LOG_##severity))
+
+// Returns true if writing messages with the given verbosity is enabled in the
+// global logger. |verbosity| is positive number.
+#define FX_VLOG_IS_ENABLED(verbosity) (fx_log_is_enabled(-(verbosity)))
+
+#define _FX_LOG_SET_SEVERITY(severity)                      \
+    do {                                                    \
+        fx_logger_t* logger = fx_log_get_logger();          \
+        if (logger) {                                       \
+            fx_logger_set_min_severity(logger, (severity)); \
+        }                                                   \
+    } while (0)
+
+// Sets severity for global logger.
+// |severity| is one of DEBUG, INFO, WARNING, ERROR, or FATAL.
+#define FX_LOG_SET_SEVERITY(severity) _FX_LOG_SET_SEVERITY(FX_LOG_##severity)
+
+// Sets verbosity for global logger.
+// |verbosity| is positive number. Logger severity is set to -verbosity
+#define FX_LOG_SET_VERBOSITY(verbosity) _FX_LOG_SET_SEVERITY(-(verbosity))
+
+#define _FX_LOG(severity, tag, message)                                   \
+    do {                                                                  \
+        fx_logger_t* logger = fx_log_get_logger();                        \
+        if (logger && fx_logger_get_min_severity(logger) <= (severity)) { \
+            fx_logger_log(logger, (severity), (tag), (message));          \
+        }                                                                 \
+    } while (0)
+
+#define _FX_LOGF(severity, tag, message, ...)                             \
+    do {                                                                  \
+        fx_logger_t* logger = fx_log_get_logger();                        \
+        if (logger && fx_logger_get_min_severity(logger) <= (severity)) { \
+            fx_logger_logf(logger, (severity), (tag), (message),          \
+                           __VA_ARGS__);                                  \
+        }                                                                 \
+    } while (0)
+
+#define _FX_LOGVF(severity, tag, message, args)                            \
+    do {                                                                   \
+        fx_logger_t* logger = fx_log_get_logger();                         \
+        if (logger && fx_logger_get_min_severity(logger) <= (severity)) {  \
+            fx_logger_logvf(logger, (severity), (tag), (message), (args)); \
+        }                                                                  \
+    } while (0)
+
+// Writes a message to the global logger.
+// |severity| is one of DEBUG, INFO, WARNING, ERROR, FATAL
+// |tag| is a tag to associated with the message, or NULL if none.
+// |message| is the message to write, or NULL if none.
+#define FX_LOG(severity, tag, message) _FX_LOG((FX_LOG_##severity), tag, message)
+
+// Writes formatted message to the global logger.
+// |severity| is one of DEBUG, INFO, WARNING, ERROR, FATAL
+// |tag| is a tag to associated with the message, or NULL if none.
+// |message| is the message to write, or NULL if none.
+#define FX_LOGF(severity, tag, message, ...) _FX_LOGF((FX_LOG_##severity), tag, message, __VA_ARGS__)
+
+// Writes formatted message to the global logger using vaargs
+// |severity| is one of DEBUG, INFO, WARNING, ERROR, FATAL
+// |tag| is a tag to associated with the message, or NULL if none.
+// |message| is the message to write, or NULL if none.
+// |args| are the arguments to |message|.
+#define FX_LOGVF(severity, tag, message, args) _FX_LOGVF((FX_LOG_##severity), tag, message, args)
+
+// Writes verbose message to the global logger.
+// |verbosity| is positive integer.
+// |tag| is a tag to associated with the message, or NULL if none.
+// |message| is the message to write, or NULL if none.
+#define FX_VLOG(verbosity, tag, message) _FX_LOG(-(verbosity), tag, message)
+
+// Writes formatted verbose message to the global logger.
+// |verbosity| is positive integer.
+// |tag| is a tag to associated with the message, or NULL if none.
+// |message| is the message to write, or NULL if none.
+#define FX_VLOGF(verbosity, tag, message, ...) _FX_LOGF(-(verbosity), tag, message, __VA_ARGS__)
+
+// Writes formatted verbose message to the global logger using vaargs
+// |verbosity| is positive integer.
+// |tag| is a tag to associated with the message, or NULL if none.
+// |message| is the message to write, or NULL if none.
+// |args| are the arguments to |message|.
+#define FX_VLOGVF(verbosity, tag, message, args) _FX_LOGVF(-(verbosity), tag, message, args)
+
+__END_CDECLS
+
+#endif // LIB_SYSLOG_GLOBAL_H_
diff --git a/pkg/syslog/include/lib/syslog/logger.h b/pkg/syslog/include/lib/syslog/logger.h
new file mode 100644
index 0000000..26e001a
--- /dev/null
+++ b/pkg/syslog/include/lib/syslog/logger.h
@@ -0,0 +1,126 @@
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+//
+// This header contains definition for the logger object and protocol.
+
+#ifndef LIB_SYSLOG_LOGGER_H_
+#define LIB_SYSLOG_LOGGER_H_
+
+#include <stdarg.h>
+#include <unistd.h>
+
+#include <zircon/types.h>
+
+// Max no of tags associated with a logger.
+#define FX_LOG_MAX_TAGS (4)
+
+// Max individual tag length including terminating character.
+#define FX_LOG_MAX_TAG_LEN (64)
+
+// Log entry severity.
+// Used for coarse filtering of log messages
+typedef int fx_log_severity_t;
+#define FX_LOG_INFO (0)
+#define FX_LOG_WARNING (1)
+#define FX_LOG_ERROR (2)
+#define FX_LOG_FATAL (3)
+
+__BEGIN_CDECLS
+
+// Configuration for a logger object.
+// Specifies the destination to which log messages should be written.
+// Multiple destinations may be used concurrently.
+typedef struct fx_logger_config {
+    // The minimum log severity.
+    // Log messages with lower severity will be discarded.
+    fx_log_severity_t min_severity;
+
+    // The file descriptor to which formatted log messages should be written,
+    // or -1 if log messages should not be written to the console.
+    // logger takes ownership of this fd.
+    int console_fd;
+
+    // The FIDL log service channel to which the logger should connect, or
+    // |ZX_HANDLE_INVALID| if the logger should not connect to the log service.
+    // logger takes ownership of this handle.
+    zx_handle_t log_service_channel;
+
+    // An array of tag strings to associate with all messages written
+    // by this logger.  Tags will be truncated if they are (individually) longer
+    // than |FX_LOG_MAX_TAG_LEN|.
+    const char** tags;
+
+    // Number of tag strings.  Must be no more than |FX_LOG_MAX_TAGS|.
+    size_t num_tags;
+} fx_logger_config_t;
+
+// Opaque type representing a logger object.
+typedef struct fx_logger fx_logger_t;
+
+// Creates a logger object from the specified configuration.
+//
+// This will return ZX_ERR_INVALID_ARGS if |num_tags| is more than
+// |FX_LOG_MAX_TAGS| and return |ZX_ERR_INTERNAL} if dup fails.
+// |config| can be safely deleted after this function returns.
+zx_status_t fx_logger_create(const fx_logger_config_t* config,
+                             fx_logger_t** out_logger);
+
+// Destroys a logger object.
+//
+// This closes |console_fd| or |log_service_channel| which were passed in
+// |fx_logger_config_t|.
+void fx_logger_destroy(fx_logger_t* logger);
+
+// Gets the logger's minimum log severity.
+fx_log_severity_t fx_logger_get_min_severity(fx_logger_t* logger);
+
+// Sets logger severity
+void fx_logger_set_min_severity(fx_logger_t* logger,
+                                fx_log_severity_t severity);
+
+// Activates fallback mode and logger starts writing to |fallback_fd|.
+// There is no way to revert this action.
+//
+// This function does not take ownership of |fallback_fd| and it should not be
+// closed till this logger object is no longer in use. Logger will log to
+// stderr if -1 is provided.
+//
+// This function is thread unsafe.
+void fx_logger_activate_fallback(fx_logger_t* logger,
+                                 int fallback_fd);
+
+// Writes formatted message to a logger.
+// The message will be discarded if |severity| is less than the logger's
+// minimum log severity.
+// The |tag| may be NULL, in which case no additional tags are added to the
+// log message.
+// The |tag| will be truncated if it is longer than |FX_LOG_MAX_TAG_LEN|.
+// No message is written if |message| is NULL.
+zx_status_t fx_logger_logf(fx_logger_t* logger, fx_log_severity_t severity,
+                           const char* tag, const char* msg, ...);
+
+// Writes formatted message to a logger using varargs.
+// The message will be discarded if |severity| is less than the logger's
+// minimum log severity.
+// The |tag| may be NULL, in which case no additional tags are added to the
+// log message.
+// The |tag| will be truncated if it is longer than |FX_LOG_MAX_TAG_LEN|.
+// No message is written if |message| is NULL.
+zx_status_t fx_logger_logvf(fx_logger_t* logger, fx_log_severity_t severity,
+                            const char* tag, const char* msg, va_list args);
+
+// Writes a message to a logger.
+// The message will be discarded if |severity| is less than the logger's
+// minimum log severity.
+// The |tag| may be NULL, in which case no additional tags are added to the
+// log message.
+// The |tag| will be truncated if it is longer than |FX_LOG_MAX_TAG_LEN|.
+// No message is written if |message| is NULL.
+zx_status_t fx_logger_log(fx_logger_t* logger, fx_log_severity_t severity,
+                          const char* tag, const char* msg);
+
+__END_CDECLS
+
+#endif // LIB_SYSLOG_LOGGER_H_
diff --git a/pkg/syslog/include/lib/syslog/wire_format.h b/pkg/syslog/include/lib/syslog/wire_format.h
new file mode 100644
index 0000000..33dbff0
--- /dev/null
+++ b/pkg/syslog/include/lib/syslog/wire_format.h
@@ -0,0 +1,38 @@
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// This header file defines wire format to transfer logs to listening service.
+
+#ifndef LIB_SYSLOG_WIRE_FORMAT_H_
+#define LIB_SYSLOG_WIRE_FORMAT_H_
+
+#include <lib/syslog/logger.h>
+#include <zircon/types.h>
+
+// Defines max length for storing log_metadata, tags and msgbuffer.
+// TODO(anmittal): Increase it when zircon sockets are able to support a higher
+// buffer.
+#define FX_LOG_MAX_DATAGRAM_LEN (2032)
+
+typedef struct fx_log_metadata {
+    zx_koid_t pid;
+    zx_koid_t tid;
+    zx_time_t time;
+    fx_log_severity_t severity;
+
+    // Increment this field whenever there is a socket write error and client
+    // drops the log and send it with next log msg.
+    uint32_t dropped_logs;
+} fx_log_metadata_t;
+
+// Packet to transfer over socket.
+typedef struct fx_log_packet {
+    fx_log_metadata_t metadata;
+
+    // Contains concatenated tags and message and a null terminating character at
+    // the end.
+    char data[FX_LOG_MAX_DATAGRAM_LEN - sizeof(fx_log_metadata_t)];
+} fx_log_packet_t;
+
+#endif // LIB_SYSLOG_WIRE_FORMAT_H_
diff --git a/pkg/syslog/meta.json b/pkg/syslog/meta.json
new file mode 100644
index 0000000..e427a70
--- /dev/null
+++ b/pkg/syslog/meta.json
@@ -0,0 +1,27 @@
+{
+  "binaries": {
+    "arm64": {
+      "debug": ".build-id/ab/d169689a6ad6a1155ae97b4155fa92810bfdce.debug", 
+      "dist": "arch/arm64/dist/libsyslog.so", 
+      "link": "arch/arm64/lib/libsyslog.so"
+    }, 
+    "x64": {
+      "debug": ".build-id/6c/dab7364d696b10a4fdeb1f6c64eac9c8f707f5.debug", 
+      "dist": "arch/x64/dist/libsyslog.so", 
+      "link": "arch/x64/lib/libsyslog.so"
+    }
+  }, 
+  "deps": [
+    "fdio"
+  ], 
+  "format": "shared", 
+  "headers": [
+    "pkg/syslog/include/lib/syslog/global.h", 
+    "pkg/syslog/include/lib/syslog/logger.h", 
+    "pkg/syslog/include/lib/syslog/wire_format.h"
+  ], 
+  "include_dir": "pkg/syslog/include", 
+  "name": "syslog", 
+  "root": "pkg/syslog", 
+  "type": "cc_prebuilt_library"
+}
\ No newline at end of file
diff --git a/pkg/sysroot/meta.json b/pkg/sysroot/meta.json
new file mode 100644
index 0000000..3219922
--- /dev/null
+++ b/pkg/sysroot/meta.json
@@ -0,0 +1,539 @@
+{
+  "name": "sysroot", 
+  "root": "pkg/sysroot", 
+  "type": "sysroot", 
+  "versions": {
+    "arm64": {
+      "debug_libs": [
+        "arch/arm64/sysroot/debug/libc.so", 
+        "arch/arm64/sysroot/debug/libzircon.so"
+      ], 
+      "dist_libs": [
+        "arch/arm64/sysroot/dist/lib/ld.so.1"
+      ], 
+      "headers": [
+        "arch/arm64/sysroot/include/alloca.h", 
+        "arch/arm64/sysroot/include/ar.h", 
+        "arch/arm64/sysroot/include/arpa/ftp.h", 
+        "arch/arm64/sysroot/include/arpa/inet.h", 
+        "arch/arm64/sysroot/include/arpa/nameser.h", 
+        "arch/arm64/sysroot/include/arpa/nameser_compat.h", 
+        "arch/arm64/sysroot/include/arpa/telnet.h", 
+        "arch/arm64/sysroot/include/arpa/tftp.h", 
+        "arch/arm64/sysroot/include/assert.h", 
+        "arch/arm64/sysroot/include/bits/aarch64/endian.h", 
+        "arch/arm64/sysroot/include/bits/aarch64/fenv.h", 
+        "arch/arm64/sysroot/include/bits/aarch64/float.h", 
+        "arch/arm64/sysroot/include/bits/aarch64/io.h", 
+        "arch/arm64/sysroot/include/bits/aarch64/ioctl.h", 
+        "arch/arm64/sysroot/include/bits/aarch64/ipc.h", 
+        "arch/arm64/sysroot/include/bits/aarch64/reg.h", 
+        "arch/arm64/sysroot/include/bits/aarch64/setjmp.h", 
+        "arch/arm64/sysroot/include/bits/aarch64/signal.h", 
+        "arch/arm64/sysroot/include/bits/aarch64/stat.h", 
+        "arch/arm64/sysroot/include/bits/alltypes.h", 
+        "arch/arm64/sysroot/include/bits/endian.h", 
+        "arch/arm64/sysroot/include/bits/errno.h", 
+        "arch/arm64/sysroot/include/bits/fcntl.h", 
+        "arch/arm64/sysroot/include/bits/fenv.h", 
+        "arch/arm64/sysroot/include/bits/float.h", 
+        "arch/arm64/sysroot/include/bits/io.h", 
+        "arch/arm64/sysroot/include/bits/ioctl.h", 
+        "arch/arm64/sysroot/include/bits/ipc.h", 
+        "arch/arm64/sysroot/include/bits/limits.h", 
+        "arch/arm64/sysroot/include/bits/msg.h", 
+        "arch/arm64/sysroot/include/bits/null.h", 
+        "arch/arm64/sysroot/include/bits/poll.h", 
+        "arch/arm64/sysroot/include/bits/posix.h", 
+        "arch/arm64/sysroot/include/bits/reg.h", 
+        "arch/arm64/sysroot/include/bits/resource.h", 
+        "arch/arm64/sysroot/include/bits/sem.h", 
+        "arch/arm64/sysroot/include/bits/setjmp.h", 
+        "arch/arm64/sysroot/include/bits/shm.h", 
+        "arch/arm64/sysroot/include/bits/signal.h", 
+        "arch/arm64/sysroot/include/bits/socket.h", 
+        "arch/arm64/sysroot/include/bits/stat.h", 
+        "arch/arm64/sysroot/include/bits/statfs.h", 
+        "arch/arm64/sysroot/include/bits/termios.h", 
+        "arch/arm64/sysroot/include/bits/x86_64/endian.h", 
+        "arch/arm64/sysroot/include/bits/x86_64/fenv.h", 
+        "arch/arm64/sysroot/include/bits/x86_64/float.h", 
+        "arch/arm64/sysroot/include/bits/x86_64/io.h", 
+        "arch/arm64/sysroot/include/bits/x86_64/ioctl.h", 
+        "arch/arm64/sysroot/include/bits/x86_64/ipc.h", 
+        "arch/arm64/sysroot/include/bits/x86_64/reg.h", 
+        "arch/arm64/sysroot/include/bits/x86_64/setjmp.h", 
+        "arch/arm64/sysroot/include/bits/x86_64/signal.h", 
+        "arch/arm64/sysroot/include/bits/x86_64/stat.h", 
+        "arch/arm64/sysroot/include/byteswap.h", 
+        "arch/arm64/sysroot/include/complex.h", 
+        "arch/arm64/sysroot/include/cpio.h", 
+        "arch/arm64/sysroot/include/crypt.h", 
+        "arch/arm64/sysroot/include/ctype.h", 
+        "arch/arm64/sysroot/include/dirent.h", 
+        "arch/arm64/sysroot/include/dlfcn.h", 
+        "arch/arm64/sysroot/include/elf.h", 
+        "arch/arm64/sysroot/include/endian.h", 
+        "arch/arm64/sysroot/include/err.h", 
+        "arch/arm64/sysroot/include/errno.h", 
+        "arch/arm64/sysroot/include/fcntl.h", 
+        "arch/arm64/sysroot/include/features.h", 
+        "arch/arm64/sysroot/include/fenv.h", 
+        "arch/arm64/sysroot/include/float.h", 
+        "arch/arm64/sysroot/include/fmtmsg.h", 
+        "arch/arm64/sysroot/include/fnmatch.h", 
+        "arch/arm64/sysroot/include/ftw.h", 
+        "arch/arm64/sysroot/include/getopt.h", 
+        "arch/arm64/sysroot/include/glob.h", 
+        "arch/arm64/sysroot/include/grp.h", 
+        "arch/arm64/sysroot/include/iconv.h", 
+        "arch/arm64/sysroot/include/ifaddrs.h", 
+        "arch/arm64/sysroot/include/inttypes.h", 
+        "arch/arm64/sysroot/include/iso646.h", 
+        "arch/arm64/sysroot/include/langinfo.h", 
+        "arch/arm64/sysroot/include/libgen.h", 
+        "arch/arm64/sysroot/include/limits.h", 
+        "arch/arm64/sysroot/include/link.h", 
+        "arch/arm64/sysroot/include/locale.h", 
+        "arch/arm64/sysroot/include/malloc.h", 
+        "arch/arm64/sysroot/include/math.h", 
+        "arch/arm64/sysroot/include/memory.h", 
+        "arch/arm64/sysroot/include/monetary.h", 
+        "arch/arm64/sysroot/include/net/ethernet.h", 
+        "arch/arm64/sysroot/include/net/if.h", 
+        "arch/arm64/sysroot/include/net/if_arp.h", 
+        "arch/arm64/sysroot/include/net/route.h", 
+        "arch/arm64/sysroot/include/netdb.h", 
+        "arch/arm64/sysroot/include/netinet/ether.h", 
+        "arch/arm64/sysroot/include/netinet/icmp6.h", 
+        "arch/arm64/sysroot/include/netinet/if_ether.h", 
+        "arch/arm64/sysroot/include/netinet/igmp.h", 
+        "arch/arm64/sysroot/include/netinet/in.h", 
+        "arch/arm64/sysroot/include/netinet/in_systm.h", 
+        "arch/arm64/sysroot/include/netinet/ip.h", 
+        "arch/arm64/sysroot/include/netinet/ip6.h", 
+        "arch/arm64/sysroot/include/netinet/ip_icmp.h", 
+        "arch/arm64/sysroot/include/netinet/tcp.h", 
+        "arch/arm64/sysroot/include/netinet/udp.h", 
+        "arch/arm64/sysroot/include/netpacket/packet.h", 
+        "arch/arm64/sysroot/include/nl_types.h", 
+        "arch/arm64/sysroot/include/paths.h", 
+        "arch/arm64/sysroot/include/poll.h", 
+        "arch/arm64/sysroot/include/pthread.h", 
+        "arch/arm64/sysroot/include/pty.h", 
+        "arch/arm64/sysroot/include/pwd.h", 
+        "arch/arm64/sysroot/include/regex.h", 
+        "arch/arm64/sysroot/include/resolv.h", 
+        "arch/arm64/sysroot/include/sched.h", 
+        "arch/arm64/sysroot/include/search.h", 
+        "arch/arm64/sysroot/include/semaphore.h", 
+        "arch/arm64/sysroot/include/setjmp.h", 
+        "arch/arm64/sysroot/include/signal.h", 
+        "arch/arm64/sysroot/include/spawn.h", 
+        "arch/arm64/sysroot/include/stdio.h", 
+        "arch/arm64/sysroot/include/stdlib.h", 
+        "arch/arm64/sysroot/include/stdnoreturn.h", 
+        "arch/arm64/sysroot/include/string.h", 
+        "arch/arm64/sysroot/include/strings.h", 
+        "arch/arm64/sysroot/include/stropts.h", 
+        "arch/arm64/sysroot/include/sys/acct.h", 
+        "arch/arm64/sysroot/include/sys/auxv.h", 
+        "arch/arm64/sysroot/include/sys/dir.h", 
+        "arch/arm64/sysroot/include/sys/errno.h", 
+        "arch/arm64/sysroot/include/sys/eventfd.h", 
+        "arch/arm64/sysroot/include/sys/fcntl.h", 
+        "arch/arm64/sysroot/include/sys/file.h", 
+        "arch/arm64/sysroot/include/sys/fsuid.h", 
+        "arch/arm64/sysroot/include/sys/io.h", 
+        "arch/arm64/sysroot/include/sys/ioctl.h", 
+        "arch/arm64/sysroot/include/sys/ipc.h", 
+        "arch/arm64/sysroot/include/sys/klog.h", 
+        "arch/arm64/sysroot/include/sys/mman.h", 
+        "arch/arm64/sysroot/include/sys/mount.h", 
+        "arch/arm64/sysroot/include/sys/msg.h", 
+        "arch/arm64/sysroot/include/sys/mtio.h", 
+        "arch/arm64/sysroot/include/sys/param.h", 
+        "arch/arm64/sysroot/include/sys/personality.h", 
+        "arch/arm64/sysroot/include/sys/poll.h", 
+        "arch/arm64/sysroot/include/sys/quota.h", 
+        "arch/arm64/sysroot/include/sys/random.h", 
+        "arch/arm64/sysroot/include/sys/reboot.h", 
+        "arch/arm64/sysroot/include/sys/reg.h", 
+        "arch/arm64/sysroot/include/sys/select.h", 
+        "arch/arm64/sysroot/include/sys/sem.h", 
+        "arch/arm64/sysroot/include/sys/sendfile.h", 
+        "arch/arm64/sysroot/include/sys/shm.h", 
+        "arch/arm64/sysroot/include/sys/signal.h", 
+        "arch/arm64/sysroot/include/sys/signalfd.h", 
+        "arch/arm64/sysroot/include/sys/socket.h", 
+        "arch/arm64/sysroot/include/sys/stat.h", 
+        "arch/arm64/sysroot/include/sys/statfs.h", 
+        "arch/arm64/sysroot/include/sys/statvfs.h", 
+        "arch/arm64/sysroot/include/sys/stropts.h", 
+        "arch/arm64/sysroot/include/sys/swap.h", 
+        "arch/arm64/sysroot/include/sys/syslog.h", 
+        "arch/arm64/sysroot/include/sys/termios.h", 
+        "arch/arm64/sysroot/include/sys/time.h", 
+        "arch/arm64/sysroot/include/sys/timeb.h", 
+        "arch/arm64/sysroot/include/sys/timerfd.h", 
+        "arch/arm64/sysroot/include/sys/times.h", 
+        "arch/arm64/sysroot/include/sys/timex.h", 
+        "arch/arm64/sysroot/include/sys/ttydefaults.h", 
+        "arch/arm64/sysroot/include/sys/types.h", 
+        "arch/arm64/sysroot/include/sys/ucontext.h", 
+        "arch/arm64/sysroot/include/sys/uio.h", 
+        "arch/arm64/sysroot/include/sys/un.h", 
+        "arch/arm64/sysroot/include/sys/utsname.h", 
+        "arch/arm64/sysroot/include/sys/vfs.h", 
+        "arch/arm64/sysroot/include/sys/wait.h", 
+        "arch/arm64/sysroot/include/sysexits.h", 
+        "arch/arm64/sysroot/include/syslog.h", 
+        "arch/arm64/sysroot/include/tar.h", 
+        "arch/arm64/sysroot/include/termios.h", 
+        "arch/arm64/sysroot/include/threads.h", 
+        "arch/arm64/sysroot/include/time.h", 
+        "arch/arm64/sysroot/include/uchar.h", 
+        "arch/arm64/sysroot/include/ucontext.h", 
+        "arch/arm64/sysroot/include/unistd.h", 
+        "arch/arm64/sysroot/include/utime.h", 
+        "arch/arm64/sysroot/include/values.h", 
+        "arch/arm64/sysroot/include/wait.h", 
+        "arch/arm64/sysroot/include/wchar.h", 
+        "arch/arm64/sysroot/include/wctype.h", 
+        "arch/arm64/sysroot/include/wordexp.h", 
+        "arch/arm64/sysroot/include/zircon/assert.h", 
+        "arch/arm64/sysroot/include/zircon/boot/bootdata.h", 
+        "arch/arm64/sysroot/include/zircon/boot/driver-config.h", 
+        "arch/arm64/sysroot/include/zircon/boot/e820.h", 
+        "arch/arm64/sysroot/include/zircon/boot/image.h", 
+        "arch/arm64/sysroot/include/zircon/boot/multiboot.h", 
+        "arch/arm64/sysroot/include/zircon/boot/netboot.h", 
+        "arch/arm64/sysroot/include/zircon/boot/sysconfig.h", 
+        "arch/arm64/sysroot/include/zircon/compiler.h", 
+        "arch/arm64/sysroot/include/zircon/device/ioctl-wrapper.h", 
+        "arch/arm64/sysroot/include/zircon/device/ioctl.h", 
+        "arch/arm64/sysroot/include/zircon/device/ramdisk.h", 
+        "arch/arm64/sysroot/include/zircon/dlfcn.h", 
+        "arch/arm64/sysroot/include/zircon/driver/binding.h", 
+        "arch/arm64/sysroot/include/zircon/errors.h", 
+        "arch/arm64/sysroot/include/zircon/features.h", 
+        "arch/arm64/sysroot/include/zircon/fidl.h", 
+        "arch/arm64/sysroot/include/zircon/hw/gpt.h", 
+        "arch/arm64/sysroot/include/zircon/hw/i2c.h", 
+        "arch/arm64/sysroot/include/zircon/hw/pci.h", 
+        "arch/arm64/sysroot/include/zircon/hw/usb-audio.h", 
+        "arch/arm64/sysroot/include/zircon/hw/usb-cdc.h", 
+        "arch/arm64/sysroot/include/zircon/hw/usb-hid.h", 
+        "arch/arm64/sysroot/include/zircon/hw/usb-hub.h", 
+        "arch/arm64/sysroot/include/zircon/hw/usb-mass-storage.h", 
+        "arch/arm64/sysroot/include/zircon/hw/usb-video.h", 
+        "arch/arm64/sysroot/include/zircon/hw/usb.h", 
+        "arch/arm64/sysroot/include/zircon/limits.h", 
+        "arch/arm64/sysroot/include/zircon/listnode.h", 
+        "arch/arm64/sysroot/include/zircon/pixelformat.h", 
+        "arch/arm64/sysroot/include/zircon/process.h", 
+        "arch/arm64/sysroot/include/zircon/processargs.h", 
+        "arch/arm64/sysroot/include/zircon/rights.h", 
+        "arch/arm64/sysroot/include/zircon/sanitizer.h", 
+        "arch/arm64/sysroot/include/zircon/status.h", 
+        "arch/arm64/sysroot/include/zircon/syscalls.h", 
+        "arch/arm64/sysroot/include/zircon/syscalls/debug.h", 
+        "arch/arm64/sysroot/include/zircon/syscalls/definitions.h", 
+        "arch/arm64/sysroot/include/zircon/syscalls/exception.h", 
+        "arch/arm64/sysroot/include/zircon/syscalls/hypervisor.h", 
+        "arch/arm64/sysroot/include/zircon/syscalls/iommu.h", 
+        "arch/arm64/sysroot/include/zircon/syscalls/log.h", 
+        "arch/arm64/sysroot/include/zircon/syscalls/object.h", 
+        "arch/arm64/sysroot/include/zircon/syscalls/pci.h", 
+        "arch/arm64/sysroot/include/zircon/syscalls/policy.h", 
+        "arch/arm64/sysroot/include/zircon/syscalls/port.h", 
+        "arch/arm64/sysroot/include/zircon/syscalls/profile.h", 
+        "arch/arm64/sysroot/include/zircon/syscalls/resource.h", 
+        "arch/arm64/sysroot/include/zircon/syscalls/smc.h", 
+        "arch/arm64/sysroot/include/zircon/syscalls/system.h", 
+        "arch/arm64/sysroot/include/zircon/syscalls/types.h", 
+        "arch/arm64/sysroot/include/zircon/threads.h", 
+        "arch/arm64/sysroot/include/zircon/time.h", 
+        "arch/arm64/sysroot/include/zircon/tls.h", 
+        "arch/arm64/sysroot/include/zircon/types.h"
+      ], 
+      "include_dir": "arch/arm64/sysroot/include", 
+      "link_libs": [
+        "arch/arm64/sysroot/lib/Scrt1.o", 
+        "arch/arm64/sysroot/lib/libc.so", 
+        "arch/arm64/sysroot/lib/libdl.so", 
+        "arch/arm64/sysroot/lib/libm.so", 
+        "arch/arm64/sysroot/lib/libpthread.so", 
+        "arch/arm64/sysroot/lib/librt.so", 
+        "arch/arm64/sysroot/lib/libzircon.so"
+      ], 
+      "root": "arch/arm64/sysroot"
+    }, 
+    "x64": {
+      "debug_libs": [
+        "arch/x64/sysroot/debug/libc.so", 
+        "arch/x64/sysroot/debug/libzircon.so"
+      ], 
+      "dist_libs": [
+        "arch/x64/sysroot/dist/lib/ld.so.1"
+      ], 
+      "headers": [
+        "arch/x64/sysroot/include/alloca.h", 
+        "arch/x64/sysroot/include/ar.h", 
+        "arch/x64/sysroot/include/arpa/ftp.h", 
+        "arch/x64/sysroot/include/arpa/inet.h", 
+        "arch/x64/sysroot/include/arpa/nameser.h", 
+        "arch/x64/sysroot/include/arpa/nameser_compat.h", 
+        "arch/x64/sysroot/include/arpa/telnet.h", 
+        "arch/x64/sysroot/include/arpa/tftp.h", 
+        "arch/x64/sysroot/include/assert.h", 
+        "arch/x64/sysroot/include/bits/aarch64/endian.h", 
+        "arch/x64/sysroot/include/bits/aarch64/fenv.h", 
+        "arch/x64/sysroot/include/bits/aarch64/float.h", 
+        "arch/x64/sysroot/include/bits/aarch64/io.h", 
+        "arch/x64/sysroot/include/bits/aarch64/ioctl.h", 
+        "arch/x64/sysroot/include/bits/aarch64/ipc.h", 
+        "arch/x64/sysroot/include/bits/aarch64/reg.h", 
+        "arch/x64/sysroot/include/bits/aarch64/setjmp.h", 
+        "arch/x64/sysroot/include/bits/aarch64/signal.h", 
+        "arch/x64/sysroot/include/bits/aarch64/stat.h", 
+        "arch/x64/sysroot/include/bits/alltypes.h", 
+        "arch/x64/sysroot/include/bits/endian.h", 
+        "arch/x64/sysroot/include/bits/errno.h", 
+        "arch/x64/sysroot/include/bits/fcntl.h", 
+        "arch/x64/sysroot/include/bits/fenv.h", 
+        "arch/x64/sysroot/include/bits/float.h", 
+        "arch/x64/sysroot/include/bits/io.h", 
+        "arch/x64/sysroot/include/bits/ioctl.h", 
+        "arch/x64/sysroot/include/bits/ipc.h", 
+        "arch/x64/sysroot/include/bits/limits.h", 
+        "arch/x64/sysroot/include/bits/msg.h", 
+        "arch/x64/sysroot/include/bits/null.h", 
+        "arch/x64/sysroot/include/bits/poll.h", 
+        "arch/x64/sysroot/include/bits/posix.h", 
+        "arch/x64/sysroot/include/bits/reg.h", 
+        "arch/x64/sysroot/include/bits/resource.h", 
+        "arch/x64/sysroot/include/bits/sem.h", 
+        "arch/x64/sysroot/include/bits/setjmp.h", 
+        "arch/x64/sysroot/include/bits/shm.h", 
+        "arch/x64/sysroot/include/bits/signal.h", 
+        "arch/x64/sysroot/include/bits/socket.h", 
+        "arch/x64/sysroot/include/bits/stat.h", 
+        "arch/x64/sysroot/include/bits/statfs.h", 
+        "arch/x64/sysroot/include/bits/termios.h", 
+        "arch/x64/sysroot/include/bits/x86_64/endian.h", 
+        "arch/x64/sysroot/include/bits/x86_64/fenv.h", 
+        "arch/x64/sysroot/include/bits/x86_64/float.h", 
+        "arch/x64/sysroot/include/bits/x86_64/io.h", 
+        "arch/x64/sysroot/include/bits/x86_64/ioctl.h", 
+        "arch/x64/sysroot/include/bits/x86_64/ipc.h", 
+        "arch/x64/sysroot/include/bits/x86_64/reg.h", 
+        "arch/x64/sysroot/include/bits/x86_64/setjmp.h", 
+        "arch/x64/sysroot/include/bits/x86_64/signal.h", 
+        "arch/x64/sysroot/include/bits/x86_64/stat.h", 
+        "arch/x64/sysroot/include/byteswap.h", 
+        "arch/x64/sysroot/include/complex.h", 
+        "arch/x64/sysroot/include/cpio.h", 
+        "arch/x64/sysroot/include/crypt.h", 
+        "arch/x64/sysroot/include/ctype.h", 
+        "arch/x64/sysroot/include/dirent.h", 
+        "arch/x64/sysroot/include/dlfcn.h", 
+        "arch/x64/sysroot/include/elf.h", 
+        "arch/x64/sysroot/include/endian.h", 
+        "arch/x64/sysroot/include/err.h", 
+        "arch/x64/sysroot/include/errno.h", 
+        "arch/x64/sysroot/include/fcntl.h", 
+        "arch/x64/sysroot/include/features.h", 
+        "arch/x64/sysroot/include/fenv.h", 
+        "arch/x64/sysroot/include/float.h", 
+        "arch/x64/sysroot/include/fmtmsg.h", 
+        "arch/x64/sysroot/include/fnmatch.h", 
+        "arch/x64/sysroot/include/ftw.h", 
+        "arch/x64/sysroot/include/getopt.h", 
+        "arch/x64/sysroot/include/glob.h", 
+        "arch/x64/sysroot/include/grp.h", 
+        "arch/x64/sysroot/include/iconv.h", 
+        "arch/x64/sysroot/include/ifaddrs.h", 
+        "arch/x64/sysroot/include/inttypes.h", 
+        "arch/x64/sysroot/include/iso646.h", 
+        "arch/x64/sysroot/include/langinfo.h", 
+        "arch/x64/sysroot/include/libgen.h", 
+        "arch/x64/sysroot/include/limits.h", 
+        "arch/x64/sysroot/include/link.h", 
+        "arch/x64/sysroot/include/locale.h", 
+        "arch/x64/sysroot/include/malloc.h", 
+        "arch/x64/sysroot/include/math.h", 
+        "arch/x64/sysroot/include/memory.h", 
+        "arch/x64/sysroot/include/monetary.h", 
+        "arch/x64/sysroot/include/net/ethernet.h", 
+        "arch/x64/sysroot/include/net/if.h", 
+        "arch/x64/sysroot/include/net/if_arp.h", 
+        "arch/x64/sysroot/include/net/route.h", 
+        "arch/x64/sysroot/include/netdb.h", 
+        "arch/x64/sysroot/include/netinet/ether.h", 
+        "arch/x64/sysroot/include/netinet/icmp6.h", 
+        "arch/x64/sysroot/include/netinet/if_ether.h", 
+        "arch/x64/sysroot/include/netinet/igmp.h", 
+        "arch/x64/sysroot/include/netinet/in.h", 
+        "arch/x64/sysroot/include/netinet/in_systm.h", 
+        "arch/x64/sysroot/include/netinet/ip.h", 
+        "arch/x64/sysroot/include/netinet/ip6.h", 
+        "arch/x64/sysroot/include/netinet/ip_icmp.h", 
+        "arch/x64/sysroot/include/netinet/tcp.h", 
+        "arch/x64/sysroot/include/netinet/udp.h", 
+        "arch/x64/sysroot/include/netpacket/packet.h", 
+        "arch/x64/sysroot/include/nl_types.h", 
+        "arch/x64/sysroot/include/paths.h", 
+        "arch/x64/sysroot/include/poll.h", 
+        "arch/x64/sysroot/include/pthread.h", 
+        "arch/x64/sysroot/include/pty.h", 
+        "arch/x64/sysroot/include/pwd.h", 
+        "arch/x64/sysroot/include/regex.h", 
+        "arch/x64/sysroot/include/resolv.h", 
+        "arch/x64/sysroot/include/sched.h", 
+        "arch/x64/sysroot/include/search.h", 
+        "arch/x64/sysroot/include/semaphore.h", 
+        "arch/x64/sysroot/include/setjmp.h", 
+        "arch/x64/sysroot/include/signal.h", 
+        "arch/x64/sysroot/include/spawn.h", 
+        "arch/x64/sysroot/include/stdio.h", 
+        "arch/x64/sysroot/include/stdlib.h", 
+        "arch/x64/sysroot/include/stdnoreturn.h", 
+        "arch/x64/sysroot/include/string.h", 
+        "arch/x64/sysroot/include/strings.h", 
+        "arch/x64/sysroot/include/stropts.h", 
+        "arch/x64/sysroot/include/sys/acct.h", 
+        "arch/x64/sysroot/include/sys/auxv.h", 
+        "arch/x64/sysroot/include/sys/dir.h", 
+        "arch/x64/sysroot/include/sys/errno.h", 
+        "arch/x64/sysroot/include/sys/eventfd.h", 
+        "arch/x64/sysroot/include/sys/fcntl.h", 
+        "arch/x64/sysroot/include/sys/file.h", 
+        "arch/x64/sysroot/include/sys/fsuid.h", 
+        "arch/x64/sysroot/include/sys/io.h", 
+        "arch/x64/sysroot/include/sys/ioctl.h", 
+        "arch/x64/sysroot/include/sys/ipc.h", 
+        "arch/x64/sysroot/include/sys/klog.h", 
+        "arch/x64/sysroot/include/sys/mman.h", 
+        "arch/x64/sysroot/include/sys/mount.h", 
+        "arch/x64/sysroot/include/sys/msg.h", 
+        "arch/x64/sysroot/include/sys/mtio.h", 
+        "arch/x64/sysroot/include/sys/param.h", 
+        "arch/x64/sysroot/include/sys/personality.h", 
+        "arch/x64/sysroot/include/sys/poll.h", 
+        "arch/x64/sysroot/include/sys/quota.h", 
+        "arch/x64/sysroot/include/sys/random.h", 
+        "arch/x64/sysroot/include/sys/reboot.h", 
+        "arch/x64/sysroot/include/sys/reg.h", 
+        "arch/x64/sysroot/include/sys/select.h", 
+        "arch/x64/sysroot/include/sys/sem.h", 
+        "arch/x64/sysroot/include/sys/sendfile.h", 
+        "arch/x64/sysroot/include/sys/shm.h", 
+        "arch/x64/sysroot/include/sys/signal.h", 
+        "arch/x64/sysroot/include/sys/signalfd.h", 
+        "arch/x64/sysroot/include/sys/socket.h", 
+        "arch/x64/sysroot/include/sys/stat.h", 
+        "arch/x64/sysroot/include/sys/statfs.h", 
+        "arch/x64/sysroot/include/sys/statvfs.h", 
+        "arch/x64/sysroot/include/sys/stropts.h", 
+        "arch/x64/sysroot/include/sys/swap.h", 
+        "arch/x64/sysroot/include/sys/syslog.h", 
+        "arch/x64/sysroot/include/sys/termios.h", 
+        "arch/x64/sysroot/include/sys/time.h", 
+        "arch/x64/sysroot/include/sys/timeb.h", 
+        "arch/x64/sysroot/include/sys/timerfd.h", 
+        "arch/x64/sysroot/include/sys/times.h", 
+        "arch/x64/sysroot/include/sys/timex.h", 
+        "arch/x64/sysroot/include/sys/ttydefaults.h", 
+        "arch/x64/sysroot/include/sys/types.h", 
+        "arch/x64/sysroot/include/sys/ucontext.h", 
+        "arch/x64/sysroot/include/sys/uio.h", 
+        "arch/x64/sysroot/include/sys/un.h", 
+        "arch/x64/sysroot/include/sys/utsname.h", 
+        "arch/x64/sysroot/include/sys/vfs.h", 
+        "arch/x64/sysroot/include/sys/wait.h", 
+        "arch/x64/sysroot/include/sysexits.h", 
+        "arch/x64/sysroot/include/syslog.h", 
+        "arch/x64/sysroot/include/tar.h", 
+        "arch/x64/sysroot/include/termios.h", 
+        "arch/x64/sysroot/include/threads.h", 
+        "arch/x64/sysroot/include/time.h", 
+        "arch/x64/sysroot/include/uchar.h", 
+        "arch/x64/sysroot/include/ucontext.h", 
+        "arch/x64/sysroot/include/unistd.h", 
+        "arch/x64/sysroot/include/utime.h", 
+        "arch/x64/sysroot/include/values.h", 
+        "arch/x64/sysroot/include/wait.h", 
+        "arch/x64/sysroot/include/wchar.h", 
+        "arch/x64/sysroot/include/wctype.h", 
+        "arch/x64/sysroot/include/wordexp.h", 
+        "arch/x64/sysroot/include/zircon/assert.h", 
+        "arch/x64/sysroot/include/zircon/boot/bootdata.h", 
+        "arch/x64/sysroot/include/zircon/boot/driver-config.h", 
+        "arch/x64/sysroot/include/zircon/boot/e820.h", 
+        "arch/x64/sysroot/include/zircon/boot/image.h", 
+        "arch/x64/sysroot/include/zircon/boot/multiboot.h", 
+        "arch/x64/sysroot/include/zircon/boot/netboot.h", 
+        "arch/x64/sysroot/include/zircon/boot/sysconfig.h", 
+        "arch/x64/sysroot/include/zircon/compiler.h", 
+        "arch/x64/sysroot/include/zircon/device/ioctl-wrapper.h", 
+        "arch/x64/sysroot/include/zircon/device/ioctl.h", 
+        "arch/x64/sysroot/include/zircon/device/ramdisk.h", 
+        "arch/x64/sysroot/include/zircon/dlfcn.h", 
+        "arch/x64/sysroot/include/zircon/driver/binding.h", 
+        "arch/x64/sysroot/include/zircon/errors.h", 
+        "arch/x64/sysroot/include/zircon/features.h", 
+        "arch/x64/sysroot/include/zircon/fidl.h", 
+        "arch/x64/sysroot/include/zircon/hw/gpt.h", 
+        "arch/x64/sysroot/include/zircon/hw/i2c.h", 
+        "arch/x64/sysroot/include/zircon/hw/pci.h", 
+        "arch/x64/sysroot/include/zircon/hw/usb-audio.h", 
+        "arch/x64/sysroot/include/zircon/hw/usb-cdc.h", 
+        "arch/x64/sysroot/include/zircon/hw/usb-hid.h", 
+        "arch/x64/sysroot/include/zircon/hw/usb-hub.h", 
+        "arch/x64/sysroot/include/zircon/hw/usb-mass-storage.h", 
+        "arch/x64/sysroot/include/zircon/hw/usb-video.h", 
+        "arch/x64/sysroot/include/zircon/hw/usb.h", 
+        "arch/x64/sysroot/include/zircon/limits.h", 
+        "arch/x64/sysroot/include/zircon/listnode.h", 
+        "arch/x64/sysroot/include/zircon/pixelformat.h", 
+        "arch/x64/sysroot/include/zircon/process.h", 
+        "arch/x64/sysroot/include/zircon/processargs.h", 
+        "arch/x64/sysroot/include/zircon/rights.h", 
+        "arch/x64/sysroot/include/zircon/sanitizer.h", 
+        "arch/x64/sysroot/include/zircon/status.h", 
+        "arch/x64/sysroot/include/zircon/syscalls.h", 
+        "arch/x64/sysroot/include/zircon/syscalls/debug.h", 
+        "arch/x64/sysroot/include/zircon/syscalls/definitions.h", 
+        "arch/x64/sysroot/include/zircon/syscalls/exception.h", 
+        "arch/x64/sysroot/include/zircon/syscalls/hypervisor.h", 
+        "arch/x64/sysroot/include/zircon/syscalls/iommu.h", 
+        "arch/x64/sysroot/include/zircon/syscalls/log.h", 
+        "arch/x64/sysroot/include/zircon/syscalls/object.h", 
+        "arch/x64/sysroot/include/zircon/syscalls/pci.h", 
+        "arch/x64/sysroot/include/zircon/syscalls/policy.h", 
+        "arch/x64/sysroot/include/zircon/syscalls/port.h", 
+        "arch/x64/sysroot/include/zircon/syscalls/profile.h", 
+        "arch/x64/sysroot/include/zircon/syscalls/resource.h", 
+        "arch/x64/sysroot/include/zircon/syscalls/smc.h", 
+        "arch/x64/sysroot/include/zircon/syscalls/system.h", 
+        "arch/x64/sysroot/include/zircon/syscalls/types.h", 
+        "arch/x64/sysroot/include/zircon/threads.h", 
+        "arch/x64/sysroot/include/zircon/time.h", 
+        "arch/x64/sysroot/include/zircon/tls.h", 
+        "arch/x64/sysroot/include/zircon/types.h"
+      ], 
+      "include_dir": "arch/x64/sysroot/include", 
+      "link_libs": [
+        "arch/x64/sysroot/lib/Scrt1.o", 
+        "arch/x64/sysroot/lib/libc.so", 
+        "arch/x64/sysroot/lib/libdl.so", 
+        "arch/x64/sysroot/lib/libm.so", 
+        "arch/x64/sysroot/lib/libpthread.so", 
+        "arch/x64/sysroot/lib/librt.so", 
+        "arch/x64/sysroot/lib/libzircon.so"
+      ], 
+      "root": "arch/x64/sysroot"
+    }
+  }
+}
\ No newline at end of file
diff --git a/pkg/trace-engine/meta.json b/pkg/trace-engine/meta.json
new file mode 100644
index 0000000..8856e4e
--- /dev/null
+++ b/pkg/trace-engine/meta.json
@@ -0,0 +1,21 @@
+{
+  "binaries": {
+    "arm64": {
+      "debug": ".build-id/e7/2a14a0b645f41576a9d25e89239df92cd488d0.debug", 
+      "dist": "arch/arm64/dist/libtrace-engine.so", 
+      "link": "arch/arm64/lib/libtrace-engine.so"
+    }, 
+    "x64": {
+      "debug": ".build-id/db/dab49d734285639cadc0b2eb151b302ecb2edf.debug", 
+      "dist": "arch/x64/dist/libtrace-engine.so", 
+      "link": "arch/x64/lib/libtrace-engine.so"
+    }
+  }, 
+  "deps": [], 
+  "format": "shared", 
+  "headers": [], 
+  "include_dir": "pkg/trace-engine/include", 
+  "name": "trace-engine", 
+  "root": "pkg/trace-engine", 
+  "type": "cc_prebuilt_library"
+}
\ No newline at end of file
diff --git a/pkg/vulkan/meta.json b/pkg/vulkan/meta.json
new file mode 100644
index 0000000..440ecf0
--- /dev/null
+++ b/pkg/vulkan/meta.json
@@ -0,0 +1,24 @@
+{
+  "binaries": {
+    "arm64": {
+      "debug": ".build-id/13/1673e529cae5f1.debug", 
+      "dist": "arch/arm64/dist/libvulkan.so", 
+      "link": "arch/arm64/lib/libvulkan.so"
+    }, 
+    "x64": {
+      "debug": ".build-id/72/f8518d550ec0aa.debug", 
+      "dist": "arch/x64/dist/libvulkan.so", 
+      "link": "arch/x64/lib/libvulkan.so"
+    }
+  }, 
+  "deps": [
+    "fdio", 
+    "trace-engine"
+  ], 
+  "format": "shared", 
+  "headers": [], 
+  "include_dir": "pkg/vulkan/include", 
+  "name": "vulkan", 
+  "root": "pkg/vulkan", 
+  "type": "cc_prebuilt_library"
+}
\ No newline at end of file
diff --git a/pkg/vulkan_layers/data/vulkan/explicit_layer.d/VkLayer_core_validation.json b/pkg/vulkan_layers/data/vulkan/explicit_layer.d/VkLayer_core_validation.json
new file mode 100644
index 0000000..94887e6
--- /dev/null
+++ b/pkg/vulkan_layers/data/vulkan/explicit_layer.d/VkLayer_core_validation.json
@@ -0,0 +1,43 @@
+{
+    "file_format_version" : "1.1.0",
+    "layer" : {
+        "name": "VK_LAYER_LUNARG_core_validation",
+        "type": "GLOBAL",
+        "library_path": "libVkLayer_core_validation.so",
+        "api_version": "1.0.68",
+        "implementation_version": "1",
+        "description": "LunarG Validation Layer",
+        "instance_extensions": [
+             {
+                 "name": "VK_EXT_debug_report",
+                 "spec_version": "6"
+             }
+         ],
+        "device_extensions": [
+             {
+                 "name": "VK_EXT_debug_marker",
+                 "spec_version": "4",
+                 "entrypoints": ["vkDebugMarkerSetObjectTagEXT",
+                        "vkDebugMarkerSetObjectNameEXT",
+                        "vkCmdDebugMarkerBeginEXT",
+                        "vkCmdDebugMarkerEndEXT",
+                        "vkCmdDebugMarkerInsertEXT"
+                       ]
+             },
+             {
+                 "name": "VK_EXT_validation_cache",
+                 "spec_version": "1",
+                 "entrypoints": ["vkCreateValidationCacheEXT",
+                         "vkDestroyValidationCacheEXT",
+                         "vkGetValidationCacheDataEXT",
+                         "vkMergeValidationCachesEXT"
+                        ]
+             }
+         ]
+    }
+}
+
+
+
+
+
diff --git a/pkg/vulkan_layers/data/vulkan/explicit_layer.d/VkLayer_image_pipe_swapchain.json b/pkg/vulkan_layers/data/vulkan/explicit_layer.d/VkLayer_image_pipe_swapchain.json
new file mode 100644
index 0000000..7c6ebe6
--- /dev/null
+++ b/pkg/vulkan_layers/data/vulkan/explicit_layer.d/VkLayer_image_pipe_swapchain.json
@@ -0,0 +1,21 @@
+{
+    "file_format_version" : "1.0.0",
+    "layer" : {
+        "name": "VK_LAYER_GOOGLE_image_pipe_swapchain",
+        "type": "GLOBAL",
+        "library_path": "libVkLayer_image_pipe_swapchain.so",
+        "api_version": "1.0.38",
+        "implementation_version": "1",
+        "description": "Image Pipe Swapchain",
+        "disable_environment": {
+            "DISABLE_IMAGEPIPE_SWAPCHAIN_LAYER": "1"
+        },
+        "instance_extensions": [
+            { "name": "VK_KHR_surface", "spec_version": "25" },
+            { "name": "VK_KHR_magma_surface", "spec_version": "1" }
+        ],
+        "device_extensions": [
+            { "name": "VK_KHR_swapchain", "spec_version": "68" }
+        ]
+    }
+}
\ No newline at end of file
diff --git a/pkg/vulkan_layers/data/vulkan/explicit_layer.d/VkLayer_object_tracker.json b/pkg/vulkan_layers/data/vulkan/explicit_layer.d/VkLayer_object_tracker.json
new file mode 100644
index 0000000..3da8c58
--- /dev/null
+++ b/pkg/vulkan_layers/data/vulkan/explicit_layer.d/VkLayer_object_tracker.json
@@ -0,0 +1,29 @@
+{
+    "file_format_version" : "1.1.0",
+    "layer" : {
+        "name": "VK_LAYER_LUNARG_object_tracker",
+        "type": "GLOBAL",
+        "library_path": "libVkLayer_object_tracker.so",
+        "api_version": "1.0.68",
+        "implementation_version": "1",
+        "description": "LunarG Validation Layer",
+        "instance_extensions": [
+             {
+                 "name": "VK_EXT_debug_report",
+                 "spec_version": "6"
+             }
+         ],
+        "device_extensions": [
+             {
+                 "name": "VK_EXT_debug_marker",
+                 "spec_version": "4",
+                 "entrypoints": ["vkDebugMarkerSetObjectTagEXT",
+                        "vkDebugMarkerSetObjectNameEXT",
+                        "vkCmdDebugMarkerBeginEXT",
+                        "vkCmdDebugMarkerEndEXT",
+                        "vkCmdDebugMarkerInsertEXT"
+                       ]
+             }
+         ]
+    }
+}
diff --git a/pkg/vulkan_layers/data/vulkan/explicit_layer.d/VkLayer_parameter_validation.json b/pkg/vulkan_layers/data/vulkan/explicit_layer.d/VkLayer_parameter_validation.json
new file mode 100644
index 0000000..83018ed
--- /dev/null
+++ b/pkg/vulkan_layers/data/vulkan/explicit_layer.d/VkLayer_parameter_validation.json
@@ -0,0 +1,29 @@
+{
+    "file_format_version" : "1.1.0",
+    "layer" : {
+        "name": "VK_LAYER_LUNARG_parameter_validation",
+        "type": "GLOBAL",
+        "library_path": "libVkLayer_parameter_validation.so",
+        "api_version": "1.0.68",
+        "implementation_version": "1",
+        "description": "LunarG Validation Layer",
+        "instance_extensions": [
+             {
+                 "name": "VK_EXT_debug_report",
+                 "spec_version": "6"
+             }
+         ],
+        "device_extensions": [
+             {
+                 "name": "VK_EXT_debug_marker",
+                 "spec_version": "4",
+                 "entrypoints": ["vkDebugMarkerSetObjectTagEXT",
+                        "vkDebugMarkerSetObjectNameEXT",
+                        "vkCmdDebugMarkerBeginEXT",
+                        "vkCmdDebugMarkerEndEXT",
+                        "vkCmdDebugMarkerInsertEXT"
+                       ]
+             }
+         ]
+    }
+}
diff --git a/pkg/vulkan_layers/data/vulkan/explicit_layer.d/VkLayer_standard_validation.json b/pkg/vulkan_layers/data/vulkan/explicit_layer.d/VkLayer_standard_validation.json
new file mode 100644
index 0000000..ccf4189
--- /dev/null
+++ b/pkg/vulkan_layers/data/vulkan/explicit_layer.d/VkLayer_standard_validation.json
@@ -0,0 +1,17 @@
+{
+    "file_format_version": "1.1.1",
+    "layer": {
+        "name": "VK_LAYER_LUNARG_standard_validation",
+        "type": "GLOBAL",
+        "api_version": "1.0.68",
+        "implementation_version": "1",
+        "description": "LunarG Standard Validation",
+        "component_layers": [
+            "VK_LAYER_GOOGLE_threading",
+            "VK_LAYER_LUNARG_parameter_validation",
+            "VK_LAYER_LUNARG_object_tracker",
+            "VK_LAYER_LUNARG_core_validation",
+            "VK_LAYER_GOOGLE_unique_objects"
+        ]
+    }
+}
diff --git a/pkg/vulkan_layers/data/vulkan/explicit_layer.d/VkLayer_threading.json b/pkg/vulkan_layers/data/vulkan/explicit_layer.d/VkLayer_threading.json
new file mode 100644
index 0000000..2e162b2
--- /dev/null
+++ b/pkg/vulkan_layers/data/vulkan/explicit_layer.d/VkLayer_threading.json
@@ -0,0 +1,17 @@
+{
+    "file_format_version" : "1.1.0",
+    "layer" : {
+        "name": "VK_LAYER_GOOGLE_threading",
+        "type": "GLOBAL",
+        "library_path": "libVkLayer_threading.so",
+        "api_version": "1.0.68",
+        "implementation_version": "1",
+        "description": "Google Validation Layer",
+        "instance_extensions": [
+             {
+                 "name": "VK_EXT_debug_report",
+                 "spec_version": "6"
+             }
+         ]
+    }
+}
diff --git a/pkg/vulkan_layers/data/vulkan/explicit_layer.d/VkLayer_unique_objects.json b/pkg/vulkan_layers/data/vulkan/explicit_layer.d/VkLayer_unique_objects.json
new file mode 100644
index 0000000..82ad4e7
--- /dev/null
+++ b/pkg/vulkan_layers/data/vulkan/explicit_layer.d/VkLayer_unique_objects.json
@@ -0,0 +1,11 @@
+{
+    "file_format_version" : "1.1.0",
+    "layer" : {
+        "name": "VK_LAYER_GOOGLE_unique_objects",
+        "type": "GLOBAL",
+        "library_path": "libVkLayer_unique_objects.so",
+        "api_version": "1.0.68",
+        "implementation_version": "1",
+        "description": "Google Validation Layer"
+    }
+}
diff --git a/pkg/vulkan_layers/meta.json b/pkg/vulkan_layers/meta.json
new file mode 100644
index 0000000..f5355b7
--- /dev/null
+++ b/pkg/vulkan_layers/meta.json
@@ -0,0 +1,32 @@
+{
+  "binaries": {
+    "arm64": [
+      "arch/arm64/dist/libVkLayer_core_validation.so", 
+      "arch/arm64/dist/libVkLayer_threading.so", 
+      "arch/arm64/dist/libVkLayer_unique_objects.so", 
+      "arch/arm64/dist/libVkLayer_parameter_validation.so", 
+      "arch/arm64/dist/libVkLayer_object_tracker.so", 
+      "arch/arm64/dist/libVkLayer_image_pipe_swapchain.so"
+    ], 
+    "x64": [
+      "arch/x64/dist/libVkLayer_core_validation.so", 
+      "arch/x64/dist/libVkLayer_threading.so", 
+      "arch/x64/dist/libVkLayer_unique_objects.so", 
+      "arch/x64/dist/libVkLayer_parameter_validation.so", 
+      "arch/x64/dist/libVkLayer_object_tracker.so", 
+      "arch/x64/dist/libVkLayer_image_pipe_swapchain.so"
+    ]
+  }, 
+  "name": "vulkan_layers", 
+  "resources": [
+    "pkg/vulkan_layers/data/vulkan/explicit_layer.d/VkLayer_core_validation.json", 
+    "pkg/vulkan_layers/data/vulkan/explicit_layer.d/VkLayer_parameter_validation.json", 
+    "pkg/vulkan_layers/data/vulkan/explicit_layer.d/VkLayer_threading.json", 
+    "pkg/vulkan_layers/data/vulkan/explicit_layer.d/VkLayer_unique_objects.json", 
+    "pkg/vulkan_layers/data/vulkan/explicit_layer.d/VkLayer_object_tracker.json", 
+    "pkg/vulkan_layers/data/vulkan/explicit_layer.d/VkLayer_standard_validation.json", 
+    "pkg/vulkan_layers/data/vulkan/explicit_layer.d/VkLayer_image_pipe_swapchain.json"
+  ], 
+  "root": "pkg/vulkan_layers", 
+  "type": "loadable_module"
+}
\ No newline at end of file
diff --git a/pkg/zx/bti.cpp b/pkg/zx/bti.cpp
new file mode 100644
index 0000000..436177d
--- /dev/null
+++ b/pkg/zx/bti.cpp
@@ -0,0 +1,15 @@
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <lib/zx/bti.h>
+
+#include <zircon/syscalls.h>
+
+namespace zx {
+
+zx_status_t bti::create(const iommu& iommu, uint32_t options, uint64_t bti_id, bti* result) {
+    return zx_bti_create(iommu.get(), options, bti_id, result->reset_and_get_address());
+}
+
+} // namespace zx
diff --git a/pkg/zx/channel.cpp b/pkg/zx/channel.cpp
new file mode 100644
index 0000000..bbf84bb
--- /dev/null
+++ b/pkg/zx/channel.cpp
@@ -0,0 +1,25 @@
+// Copyright 2016 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <lib/zx/channel.h>
+
+#include <zircon/syscalls.h>
+
+namespace zx {
+
+zx_status_t channel::create(uint32_t flags, channel* endpoint0,
+                            channel* endpoint1) {
+    // Ensure aliasing of both out parameters to the same container
+    // has a well-defined result, and does not leak.
+    channel h0;
+    channel h1;
+    zx_status_t status = zx_channel_create(flags,
+                                           h0.reset_and_get_address(),
+                                           h1.reset_and_get_address());
+    endpoint0->reset(h0.release());
+    endpoint1->reset(h1.release());
+    return status;
+}
+
+} // namespace zx
diff --git a/pkg/zx/debuglog.cpp b/pkg/zx/debuglog.cpp
new file mode 100644
index 0000000..05ee86d
--- /dev/null
+++ b/pkg/zx/debuglog.cpp
@@ -0,0 +1,15 @@
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <lib/zx/debuglog.h>
+
+#include <zircon/syscalls.h>
+
+namespace zx {
+
+zx_status_t debuglog::create(const resource& resource, uint32_t options, debuglog* result) {
+    return zx_debuglog_create(resource.get(), options, result->reset_and_get_address());
+}
+
+} // namespace zx
diff --git a/pkg/zx/event.cpp b/pkg/zx/event.cpp
new file mode 100644
index 0000000..4539a68
--- /dev/null
+++ b/pkg/zx/event.cpp
@@ -0,0 +1,15 @@
+// Copyright 2016 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <lib/zx/event.h>
+
+#include <zircon/syscalls.h>
+
+namespace zx {
+
+zx_status_t event::create(uint32_t options, event* result) {
+    return zx_event_create(options, result->reset_and_get_address());
+}
+
+} // namespace zx
diff --git a/pkg/zx/eventpair.cpp b/pkg/zx/eventpair.cpp
new file mode 100644
index 0000000..f561e14
--- /dev/null
+++ b/pkg/zx/eventpair.cpp
@@ -0,0 +1,25 @@
+// Copyright 2016 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <lib/zx/eventpair.h>
+
+#include <zircon/syscalls.h>
+
+namespace zx {
+
+zx_status_t eventpair::create(uint32_t flags, eventpair* endpoint0,
+                              eventpair* endpoint1) {
+    // Ensure aliasing of both out parameters to the same container
+    // has a well-defined result, and does not leak.
+    eventpair h0;
+    eventpair h1;
+    zx_status_t status = zx_eventpair_create(
+        flags, h0.reset_and_get_address(),
+        h1.reset_and_get_address());
+    endpoint0->reset(h0.release());
+    endpoint1->reset(h1.release());
+    return status;
+}
+
+} // namespace zx
diff --git a/pkg/zx/fifo.cpp b/pkg/zx/fifo.cpp
new file mode 100644
index 0000000..27f965f
--- /dev/null
+++ b/pkg/zx/fifo.cpp
@@ -0,0 +1,25 @@
+// Copyright 2017 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <lib/zx/fifo.h>
+
+#include <zircon/syscalls.h>
+
+namespace zx {
+
+zx_status_t fifo::create(uint32_t elem_count, uint32_t elem_size,
+                         uint32_t options, fifo* out0, fifo* out1) {
+    // Ensure aliasing of both out parameters to the same container
+    // has a well-defined result, and does not leak.
+    fifo h0;
+    fifo h1;
+    zx_status_t status = zx_fifo_create(
+        elem_count, elem_size, options, h0.reset_and_get_address(),
+        h1.reset_and_get_address());
+    out0->reset(h0.release());
+    out1->reset(h1.release());
+    return status;
+}
+
+} // namespace zx
diff --git a/pkg/zx/guest.cpp b/pkg/zx/guest.cpp
new file mode 100644
index 0000000..f3d6029
--- /dev/null
+++ b/pkg/zx/guest.cpp
@@ -0,0 +1,22 @@
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <lib/zx/guest.h>
+
+#include <zircon/syscalls.h>
+
+#include <lib/zx/vmar.h>
+
+namespace zx {
+
+zx_status_t guest::create(const resource& resource, uint32_t options,
+                          guest* guest, vmar* vmar) {
+    // Assume |resource|, |guest| and |vmar| must refer to different containers,
+    // due to strict aliasing.
+    return zx_guest_create(
+        resource.get(), options, guest->reset_and_get_address(),
+        vmar->reset_and_get_address());
+}
+
+} // namespace zx
diff --git a/pkg/zx/include/lib/zx/bti.h b/pkg/zx/include/lib/zx/bti.h
new file mode 100644
index 0000000..0a66716
--- /dev/null
+++ b/pkg/zx/include/lib/zx/bti.h
@@ -0,0 +1,48 @@
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef LIB_ZX_BTI_H_
+#define LIB_ZX_BTI_H_
+
+#include <lib/zx/handle.h>
+#include <lib/zx/iommu.h>
+#include <lib/zx/object.h>
+#include <lib/zx/pmt.h>
+#include <lib/zx/vmo.h>
+
+namespace zx {
+
+class bti : public object<bti> {
+public:
+    static constexpr zx_obj_type_t TYPE = ZX_OBJ_TYPE_BTI;
+
+    constexpr bti() = default;
+
+    explicit bti(zx_handle_t value) : object(value) {}
+
+    explicit bti(handle&& h) : object(h.release()) {}
+
+    bti(bti&& other) : object(other.release()) {}
+
+    bti& operator=(bti&& other) {
+        reset(other.release());
+        return *this;
+    }
+
+    static zx_status_t create(const iommu& iommu, uint32_t options, uint64_t bti_id, bti* result);
+
+    zx_status_t pin(uint32_t options, const vmo& vmo, uint64_t offset, uint64_t size,
+                    zx_paddr_t* addrs, size_t addrs_count, pmt* pmt) const {
+        return zx_bti_pin(get(), options, vmo.get(), offset, size, addrs, addrs_count,
+                          pmt->reset_and_get_address());
+    }
+
+    zx_status_t release_quarantine() const { return zx_bti_release_quarantine(get()); }
+};
+
+using unowned_bti = unowned<bti>;
+
+} // namespace zx
+
+#endif  // LIB_ZX_BTI_H_
diff --git a/pkg/zx/include/lib/zx/channel.h b/pkg/zx/include/lib/zx/channel.h
new file mode 100644
index 0000000..bd28ca1
--- /dev/null
+++ b/pkg/zx/include/lib/zx/channel.h
@@ -0,0 +1,66 @@
+// Copyright 2016 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef LIB_ZX_CHANNEL_H_
+#define LIB_ZX_CHANNEL_H_
+
+#include <lib/zx/handle.h>
+#include <lib/zx/object.h>
+#include <lib/zx/time.h>
+
+namespace zx {
+
+class channel : public object<channel> {
+public:
+    static constexpr zx_obj_type_t TYPE = ZX_OBJ_TYPE_CHANNEL;
+
+    constexpr channel() = default;
+
+    explicit channel(zx_handle_t value) : object(value) {}
+
+    explicit channel(handle&& h) : object(h.release()) {}
+
+    channel(channel&& other) : object(other.release()) {}
+
+    channel& operator=(channel&& other) {
+        reset(other.release());
+        return *this;
+    }
+
+    static zx_status_t create(uint32_t flags, channel* endpoint0,
+                              channel* endpoint1);
+
+    zx_status_t read(uint32_t flags, void* bytes, uint32_t num_bytes,
+                     uint32_t* actual_bytes, zx_handle_t* handles,
+                     uint32_t num_handles, uint32_t* actual_handles) const {
+        return zx_channel_read(get(), flags, bytes, handles, num_bytes,
+                               num_handles, actual_bytes, actual_handles);
+    }
+
+    zx_status_t read_etc(uint32_t flags, void* bytes, uint32_t num_bytes,
+                         uint32_t* actual_bytes, zx_handle_info_t* handles,
+                         uint32_t num_handles, uint32_t* actual_handles) const {
+        return zx_channel_read_etc(get(), flags, bytes, handles, num_bytes,
+                                   num_handles, actual_bytes, actual_handles);
+    }
+
+    zx_status_t write(uint32_t flags, const void* bytes, uint32_t num_bytes,
+                      const zx_handle_t* handles, uint32_t num_handles) const {
+        return zx_channel_write(get(), flags, bytes, num_bytes, handles,
+                                num_handles);
+    }
+
+    zx_status_t call(uint32_t flags, zx::time deadline,
+                     const zx_channel_call_args_t* args,
+                     uint32_t* actual_bytes, uint32_t* actual_handles) const {
+        return zx_channel_call(get(), flags, deadline.get(), args, actual_bytes,
+                               actual_handles);
+    }
+};
+
+using unowned_channel = unowned<channel>;
+
+} // namespace zx
+
+#endif  // LIB_ZX_CHANNEL_H_
diff --git a/pkg/zx/include/lib/zx/debuglog.h b/pkg/zx/include/lib/zx/debuglog.h
new file mode 100644
index 0000000..1b00042
--- /dev/null
+++ b/pkg/zx/include/lib/zx/debuglog.h
@@ -0,0 +1,46 @@
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef LIB_ZX_DEBUGLOG_H_
+#define LIB_ZX_DEBUGLOG_H_
+
+#include <lib/zx/handle.h>
+#include <lib/zx/object.h>
+#include <lib/zx/resource.h>
+
+namespace zx {
+
+class debuglog : public object<debuglog> {
+public:
+    static constexpr zx_obj_type_t TYPE = ZX_OBJ_TYPE_LOG;
+
+    constexpr debuglog() = default;
+
+    explicit debuglog(zx_handle_t value) : object(value) {}
+
+    explicit debuglog(handle&& h) : object(h.release()) {}
+
+    debuglog(debuglog&& other) : object(other.release()) {}
+
+    debuglog& operator=(debuglog&& other) {
+        reset(other.release());
+        return *this;
+    }
+
+    static zx_status_t create(const resource& resource, uint32_t options, debuglog* result);
+
+    zx_status_t write(uint32_t options, const void* buffer, size_t buffer_size) const {
+        return zx_debuglog_write(get(), options, buffer, buffer_size);
+    }
+
+    zx_status_t read(uint32_t options, void* buffer, size_t buffer_size) const {
+        return zx_debuglog_read(get(), options, buffer, buffer_size);
+    }
+};
+
+using unowned_debuglog = unowned<debuglog>;
+
+} // namespace zx
+
+#endif  // LIB_ZX_DEBUGLOG_H_
diff --git a/pkg/zx/include/lib/zx/event.h b/pkg/zx/include/lib/zx/event.h
new file mode 100644
index 0000000..590c4c1
--- /dev/null
+++ b/pkg/zx/include/lib/zx/event.h
@@ -0,0 +1,37 @@
+// Copyright 2016 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef LIB_ZX_EVENT_H_
+#define LIB_ZX_EVENT_H_
+
+#include <lib/zx/handle.h>
+#include <lib/zx/object.h>
+
+namespace zx {
+
+class event : public object<event> {
+public:
+    static constexpr zx_obj_type_t TYPE = ZX_OBJ_TYPE_EVENT;
+
+    constexpr event() = default;
+
+    explicit event(zx_handle_t value) : object(value) {}
+
+    explicit event(handle&& h) : object(h.release()) {}
+
+    event(event&& other) : object(other.release()) {}
+
+    event& operator=(event&& other) {
+        reset(other.release());
+        return *this;
+    }
+
+    static zx_status_t create(uint32_t options, event* result);
+};
+
+using unowned_event = unowned<event>;
+
+} // namespace zx
+
+#endif  // LIB_ZX_EVENT_H_
diff --git a/pkg/zx/include/lib/zx/eventpair.h b/pkg/zx/include/lib/zx/eventpair.h
new file mode 100644
index 0000000..56d094a
--- /dev/null
+++ b/pkg/zx/include/lib/zx/eventpair.h
@@ -0,0 +1,38 @@
+// Copyright 2016 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef LIB_ZX_EVENTPAIR_H_
+#define LIB_ZX_EVENTPAIR_H_
+
+#include <lib/zx/handle.h>
+#include <lib/zx/object.h>
+
+namespace zx {
+
+class eventpair : public object<eventpair> {
+public:
+    static constexpr zx_obj_type_t TYPE = ZX_OBJ_TYPE_EVENTPAIR;
+
+    constexpr eventpair() = default;
+
+    explicit eventpair(zx_handle_t value) : object(value) {}
+
+    explicit eventpair(handle&& h) : object(h.release()) {}
+
+    eventpair(eventpair&& other) : object(other.release()) {}
+
+    eventpair& operator=(eventpair&& other) {
+        reset(other.release());
+        return *this;
+    }
+
+    static zx_status_t create(uint32_t options, eventpair* endpoint0,
+                              eventpair* endpoint1);
+};
+
+using unowned_eventpair = unowned<eventpair>;
+
+} // namespace zx
+
+#endif  // LIB_ZX_EVENTPAIR_H_
diff --git a/pkg/zx/include/lib/zx/fifo.h b/pkg/zx/include/lib/zx/fifo.h
new file mode 100644
index 0000000..aeab229
--- /dev/null
+++ b/pkg/zx/include/lib/zx/fifo.h
@@ -0,0 +1,47 @@
+// Copyright 2017 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef LIB_ZX_FIFO_H_
+#define LIB_ZX_FIFO_H_
+
+#include <lib/zx/handle.h>
+#include <lib/zx/object.h>
+
+namespace zx {
+
+class fifo : public object<fifo> {
+public:
+    static constexpr zx_obj_type_t TYPE = ZX_OBJ_TYPE_FIFO;
+
+    constexpr fifo() = default;
+
+    explicit fifo(zx_handle_t value) : object(value) {}
+
+    explicit fifo(handle&& h) : object(h.release()) {}
+
+    fifo(fifo&& other) : object(other.release()) {}
+
+    fifo& operator=(fifo&& other) {
+        reset(other.release());
+        return *this;
+    }
+
+    static zx_status_t create(uint32_t elem_count, uint32_t elem_size,
+                              uint32_t options, fifo* out0, fifo* out1);
+
+    zx_status_t write(size_t elem_size, const void* buffer, size_t count, size_t* actual_count) const {
+        return zx_fifo_write(get(), elem_size, buffer, count, actual_count);
+    }
+
+    zx_status_t read(size_t elem_size, void* buffer, size_t count, size_t* actual_count) const {
+        return zx_fifo_read(get(), elem_size, buffer, count, actual_count);
+    }
+
+};
+
+using unowned_fifo = unowned<fifo>;
+
+} // namespace zx
+
+#endif  // LIB_ZX_FIFO_H_
diff --git a/pkg/zx/include/lib/zx/guest.h b/pkg/zx/include/lib/zx/guest.h
new file mode 100644
index 0000000..037bc6d
--- /dev/null
+++ b/pkg/zx/include/lib/zx/guest.h
@@ -0,0 +1,46 @@
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef LIB_ZX_GUEST_H_
+#define LIB_ZX_GUEST_H_
+
+#include <lib/zx/handle.h>
+#include <lib/zx/object.h>
+#include <lib/zx/port.h>
+#include <lib/zx/resource.h>
+#include <lib/zx/vmo.h>
+
+namespace zx {
+
+class guest : public object<guest> {
+public:
+    static constexpr zx_obj_type_t TYPE = ZX_OBJ_TYPE_GUEST;
+
+    constexpr guest() = default;
+
+    explicit guest(zx_handle_t value) : object(value) {}
+
+    explicit guest(handle&& h) : object(h.release()) {}
+
+    guest(guest&& other) : object(other.release()) {}
+
+    guest& operator=(guest&& other) {
+        reset(other.release());
+        return *this;
+    }
+
+    static zx_status_t create(const resource& resource, uint32_t options,
+                              guest* guest, vmar* vmar);
+
+    zx_status_t set_trap(uint32_t kind, zx_gpaddr_t addr, size_t len,
+                         const port& port, uint64_t key) {
+        return zx_guest_set_trap(get(), kind, addr, len, port.get(), key);
+    }
+};
+
+using unowned_guest = unowned<guest>;
+
+} // namespace zx
+
+#endif  // LIB_ZX_GUEST_H_
diff --git a/pkg/zx/include/lib/zx/handle.h b/pkg/zx/include/lib/zx/handle.h
new file mode 100644
index 0000000..3daca00
--- /dev/null
+++ b/pkg/zx/include/lib/zx/handle.h
@@ -0,0 +1,17 @@
+// Copyright 2017 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef LIB_ZX_HANDLE_H_
+#define LIB_ZX_HANDLE_H_
+
+#include <lib/zx/object.h>
+
+namespace zx {
+
+using handle = object<void>;
+using unowned_handle = unowned<handle>;
+
+} // namespace zx
+
+#endif  // LIB_ZX_HANDLE_H_
diff --git a/pkg/zx/include/lib/zx/interrupt.h b/pkg/zx/include/lib/zx/interrupt.h
new file mode 100644
index 0000000..b3d3eb7
--- /dev/null
+++ b/pkg/zx/include/lib/zx/interrupt.h
@@ -0,0 +1,60 @@
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef LIB_ZX_INTERRUPT_H_
+#define LIB_ZX_INTERRUPT_H_
+
+#include <lib/zx/handle.h>
+#include <lib/zx/object.h>
+#include <lib/zx/resource.h>
+#include <lib/zx/time.h>
+
+namespace zx {
+
+class interrupt : public object<interrupt> {
+public:
+    static constexpr zx_obj_type_t TYPE = ZX_OBJ_TYPE_INTERRUPT;
+
+    constexpr interrupt() = default;
+
+    explicit interrupt(zx_handle_t value) : object(value) {}
+
+    explicit interrupt(handle&& h) : object(h.release()) {}
+
+    interrupt(interrupt&& other) : object(other.release()) {}
+
+    interrupt& operator=(interrupt&& other) {
+        reset(other.release());
+        return *this;
+    }
+
+    static zx_status_t create(const resource& resource, uint32_t vector,
+                        uint32_t options, interrupt* result);
+
+    zx_status_t wait(zx::time* timestamp) {
+        return zx_interrupt_wait(get(), timestamp->get_address());
+    }
+
+    zx_status_t destroy() {
+        return zx_interrupt_destroy(get());
+    }
+
+    zx_status_t trigger(uint32_t options, zx::time timestamp) {
+        return zx_interrupt_trigger(get(), options, timestamp.get());
+    }
+
+    zx_status_t bind(zx_handle_t porth, uint64_t key, uint32_t options) {
+        return zx_interrupt_bind(get(), porth, key, options);
+    }
+
+    zx_status_t ack() {
+        return zx_interrupt_ack(get());
+    }
+};
+
+using unowned_interrupt = unowned<interrupt>;
+
+} // namespace zx
+
+#endif  // LIB_ZX_INTERRUPT_H_
diff --git a/pkg/zx/include/lib/zx/iommu.h b/pkg/zx/include/lib/zx/iommu.h
new file mode 100644
index 0000000..95dc427
--- /dev/null
+++ b/pkg/zx/include/lib/zx/iommu.h
@@ -0,0 +1,38 @@
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef LIB_ZX_IOMMU_H_
+#define LIB_ZX_IOMMU_H_
+
+#include <lib/zx/object.h>
+#include <lib/zx/resource.h>
+
+namespace zx {
+
+class iommu : public object<iommu> {
+public:
+    static constexpr zx_obj_type_t TYPE = ZX_OBJ_TYPE_IOMMU;
+
+    constexpr iommu() = default;
+
+    explicit iommu(zx_handle_t value) : object(value) {}
+
+    explicit iommu(handle&& h) : object(h.release()) {}
+
+    iommu(iommu&& other) : object(other.release()) {}
+
+    iommu& operator=(iommu&& other) {
+        reset(other.release());
+        return *this;
+    }
+
+    static zx_status_t create(const resource& resource, uint32_t type, const void* desc,
+                              size_t desc_size, iommu* result);
+};
+
+using unowned_iommu = unowned<iommu>;
+
+} // namespace zx
+
+#endif  // LIB_ZX_IOMMU_H_
diff --git a/pkg/zx/include/lib/zx/job.h b/pkg/zx/include/lib/zx/job.h
new file mode 100644
index 0000000..3bd7125
--- /dev/null
+++ b/pkg/zx/include/lib/zx/job.h
@@ -0,0 +1,63 @@
+// Copyright 2016 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef LIB_ZX_JOB_H_
+#define LIB_ZX_JOB_H_
+
+#include <lib/zx/task.h>
+#include <zircon/process.h>
+
+namespace zx {
+
+class process;
+
+class job : public task<job> {
+public:
+    static constexpr zx_obj_type_t TYPE = ZX_OBJ_TYPE_JOB;
+
+    constexpr job() = default;
+
+    explicit job(zx_handle_t value) : task(value) {}
+
+    explicit job(handle&& h) : task(h.release()) {}
+
+    job(job&& other) : task(other.release()) {}
+
+    job& operator=(job&& other) {
+        reset(other.release());
+        return *this;
+    }
+
+    static zx_status_t create(const zx::job& parent, uint32_t options, job* result);
+
+    // Provide strongly-typed overloads, in addition to get_child(handle*).
+    using task<job>::get_child;
+    zx_status_t get_child(uint64_t koid, zx_rights_t rights,
+                          job* result) const {
+        // Allow for |result| and |this| aliasing the same container.
+        job h;
+        zx_status_t status = zx_object_get_child(
+            value_, koid, rights, h.reset_and_get_address());
+        result->reset(h.release());
+        return status;
+    }
+    zx_status_t get_child(uint64_t koid, zx_rights_t rights,
+                          process* result) const;
+
+    zx_status_t set_policy(uint32_t options, uint32_t topic, const void* policy, uint32_t count) const {
+      return zx_job_set_policy(get(), options, topic, policy, count);
+    }
+
+    // Ideally this would be called zx::job::default(), but default is a
+    // C++ keyword and cannot be used as a function name.
+    static inline unowned<job> default_job() {
+        return unowned<job>(zx_job_default());
+    }
+};
+
+using unowned_job = unowned<job>;
+
+} // namespace zx
+
+#endif  // LIB_ZX_JOB_H_
diff --git a/pkg/zx/include/lib/zx/log.h b/pkg/zx/include/lib/zx/log.h
new file mode 100644
index 0000000..36b6e22
--- /dev/null
+++ b/pkg/zx/include/lib/zx/log.h
@@ -0,0 +1,45 @@
+// Copyright 2016 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef LIB_ZX_LOG_H_
+#define LIB_ZX_LOG_H_
+
+#include <lib/zx/handle.h>
+#include <lib/zx/object.h>
+
+namespace zx {
+
+class log : public object<log> {
+public:
+    static constexpr zx_obj_type_t TYPE = ZX_OBJ_TYPE_LOG;
+
+    constexpr log() = default;
+
+    explicit log(zx_handle_t value) : object(value) {}
+
+    explicit log(handle&& h) : object(h.release()) {}
+
+    log(log&& other) : object(other.release()) {}
+
+    log& operator=(log&& other) {
+        reset(other.release());
+        return *this;
+    }
+
+    static zx_status_t create(uint32_t flags, log* result);
+
+    zx_status_t write(uint32_t len, const void* buffer, uint32_t flags) const {
+        return zx_log_write(get(), len, buffer, flags);
+    }
+
+    zx_status_t read(uint32_t len, void* buffer, uint32_t flags) const {
+        return zx_log_read(get(), len, buffer, flags);
+    }
+};
+
+using unowned_log = unowned<log>;
+
+} // namespace zx
+
+#endif  // LIB_ZX_LOG_H_
diff --git a/pkg/zx/include/lib/zx/object.h b/pkg/zx/include/lib/zx/object.h
new file mode 100644
index 0000000..57c023c
--- /dev/null
+++ b/pkg/zx/include/lib/zx/object.h
@@ -0,0 +1,319 @@
+// Copyright 2016 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef LIB_ZX_OBJECT_H_
+#define LIB_ZX_OBJECT_H_
+
+#include <zircon/syscalls.h>
+#include <zircon/types.h>
+#include <lib/zx/object_traits.h>
+#include <lib/zx/time.h>
+
+namespace zx {
+
+class port;
+class profile;
+
+// Wraps and takes ownership of a handle to an object.
+//
+// Used for code that wants to operate generically on the zx_handle_t value
+// inside a |zx::object| and doesn't otherwise need a template parameter.
+//
+// The handle is automatically closed when the wrapper is destroyed.
+class object_base {
+public:
+    void reset(zx_handle_t value = ZX_HANDLE_INVALID) {
+        close();
+        value_ = value;
+    }
+
+    bool is_valid() const { return value_ != ZX_HANDLE_INVALID; }
+    explicit operator bool() const { return is_valid(); }
+
+    zx_handle_t get() const { return value_; }
+
+    // Reset the underlying handle, and then get the address of the
+    // underlying internal handle storage.
+    //
+    // Note: The intended purpose is to facilitate interactions with C
+    // APIs which expect to be provided a pointer to a handle used as
+    // an out parameter.
+    zx_handle_t* reset_and_get_address() {
+        reset();
+        return &value_;
+    }
+
+    __attribute__((warn_unused_result)) zx_handle_t release() {
+        zx_handle_t result = value_;
+        value_ = ZX_HANDLE_INVALID;
+        return result;
+    }
+
+protected:
+    constexpr object_base() : value_(ZX_HANDLE_INVALID) {}
+
+    explicit object_base(zx_handle_t value) : value_(value) {}
+
+    ~object_base() { close(); }
+
+    object_base(const object_base&) = delete;
+
+    void operator=(const object_base&) = delete;
+
+    void close() {
+        if (value_ != ZX_HANDLE_INVALID) {
+            zx_handle_close(value_);
+            value_ = ZX_HANDLE_INVALID;
+        }
+    }
+
+    zx_handle_t value_;
+};
+
+// Provides type-safe access to operations on a handle.
+template <typename T> class object : public object_base {
+public:
+    constexpr object() = default;
+
+    explicit object(zx_handle_t value) : object_base(value) {}
+
+    template <typename U> object(object<U>&& other) : object_base(other.release()) {
+        static_assert(is_same<T, void>::value, "Receiver must be compatible.");
+    }
+
+    template <typename U> object<T>& operator=(object<U>&& other) {
+        static_assert(is_same<T, void>::value, "Receiver must be compatible.");
+        reset(other.release());
+        return *this;
+    }
+
+    void swap(object<T>& other) {
+        zx_handle_t tmp = value_;
+        value_ = other.value_;
+        other.value_ = tmp;
+    }
+
+    zx_status_t duplicate(zx_rights_t rights, object<T>* result) const {
+        static_assert(object_traits<T>::supports_duplication,
+                      "Object must support duplication.");
+        zx_handle_t h = ZX_HANDLE_INVALID;
+        zx_status_t status = zx_handle_duplicate(value_, rights, &h);
+        result->reset(h);
+        return status;
+    }
+
+    zx_status_t replace(zx_rights_t rights, object<T>* result) {
+        zx_handle_t h = ZX_HANDLE_INVALID;
+        zx_status_t status = zx_handle_replace(value_, rights, &h);
+        // We store ZX_HANDLE_INVALID to value_ before calling reset on result
+        // in case result == this.
+        value_ = ZX_HANDLE_INVALID;
+        result->reset(h);
+        return status;
+    }
+
+    zx_status_t wait_one(zx_signals_t signals, zx::time deadline,
+                         zx_signals_t* pending) const {
+        static_assert(object_traits<T>::supports_wait, "Object is not waitable.");
+        return zx_object_wait_one(value_, signals, deadline.get(), pending);
+    }
+
+    zx_status_t wait_async(const object<port>& port, uint64_t key,
+                           zx_signals_t signals, uint32_t options) const {
+        static_assert(object_traits<T>::supports_wait, "Object is not waitable.");
+        return zx_object_wait_async(value_, port.get(), key, signals, options);
+    }
+
+    static zx_status_t wait_many(zx_wait_item_t* wait_items, uint32_t count, zx::time deadline) {
+        static_assert(object_traits<T>::supports_wait, "Object is not waitable.");
+        return zx_object_wait_many(wait_items, count, deadline.get());
+    }
+
+    zx_status_t signal(uint32_t clear_mask, uint32_t set_mask) const {
+        static_assert(object_traits<T>::supports_user_signal,
+                      "Object must support user signals.");
+        return zx_object_signal(get(), clear_mask, set_mask);
+    }
+
+    zx_status_t signal_peer(uint32_t clear_mask, uint32_t set_mask) const {
+        static_assert(object_traits<T>::supports_user_signal,
+                      "Object must support user signals.");
+        static_assert(object_traits<T>::has_peer_handle,
+                      "Object must have peer object.");
+        return zx_object_signal_peer(get(), clear_mask, set_mask);
+    }
+
+    zx_status_t get_info(uint32_t topic, void* buffer,
+                         size_t buffer_size,
+                         size_t* actual_count, size_t* avail_count) const {
+        return zx_object_get_info(get(), topic, buffer, buffer_size, actual_count, avail_count);
+    }
+
+    zx_status_t get_child(uint64_t koid, zx_rights_t rights,
+                          object<void>* result) const {
+        // Allow for |result| and |this| being the same container, though that
+        // can only happen for |T=void|, due to strict aliasing.
+        object<void> h;
+        zx_status_t status = zx_object_get_child(
+            value_, koid, rights, h.reset_and_get_address());
+        result->reset(h.release());
+        return status;
+    }
+
+    zx_status_t get_property(uint32_t property, void* value,
+                             size_t size) const {
+        return zx_object_get_property(get(), property, value, size);
+    }
+
+    zx_status_t set_property(uint32_t property, const void* value,
+                             size_t size) const {
+        return zx_object_set_property(get(), property, value, size);
+    }
+
+    zx_status_t get_cookie(const object_base& scope, uint64_t *cookie) const {
+        return zx_object_get_cookie(get(), scope.get(), cookie);
+    }
+
+    zx_status_t set_cookie(const object_base& scope, uint64_t cookie) const {
+        return zx_object_set_cookie(get(), scope.get(), cookie);
+    }
+
+    zx_status_t set_profile(const object<profile>& profile, uint32_t options) const {
+        return zx_object_set_profile(get(), profile.get(), options);
+    }
+
+private:
+    template <typename A, typename B> struct is_same {
+        static const bool value = false;
+    };
+
+    template <typename A> struct is_same<A, A> {
+        static const bool value = true;
+    };
+};
+
+template <typename T> bool operator==(const object<T>& a, const object<T>& b) {
+    return a.get() == b.get();
+}
+
+template <typename T> bool operator!=(const object<T>& a, const object<T>& b) {
+    return !(a == b);
+}
+
+template <typename T> bool operator<(const object<T>& a, const object<T>& b) {
+    return a.get() < b.get();
+}
+
+template <typename T> bool operator>(const object<T>& a, const object<T>& b) {
+    return a.get() > b.get();
+}
+
+template <typename T> bool operator<=(const object<T>& a, const object<T>& b) {
+    return !(a.get() > b.get());
+}
+
+template <typename T> bool operator>=(const object<T>& a, const object<T>& b) {
+    return !(a.get() < b.get());
+}
+
+template <typename T> bool operator==(zx_handle_t a, const object<T>& b) {
+    return a == b.get();
+}
+
+template <typename T> bool operator!=(zx_handle_t a, const object<T>& b) {
+    return !(a == b);
+}
+
+template <typename T> bool operator<(zx_handle_t a, const object<T>& b) {
+    return a < b.get();
+}
+
+template <typename T> bool operator>(zx_handle_t a, const object<T>& b) {
+    return a > b.get();
+}
+
+template <typename T> bool operator<=(zx_handle_t a, const object<T>& b) {
+    return !(a > b.get());
+}
+
+template <typename T> bool operator>=(zx_handle_t a, const object<T>& b) {
+    return !(a < b.get());
+}
+
+template <typename T> bool operator==(const object<T>& a, zx_handle_t b) {
+    return a.get() == b;
+}
+
+template <typename T> bool operator!=(const object<T>& a, zx_handle_t b) {
+    return !(a == b);
+}
+
+template <typename T> bool operator<(const object<T>& a, zx_handle_t b) {
+    return a.get() < b;
+}
+
+template <typename T> bool operator>(const object<T>& a, zx_handle_t b) {
+    return a.get() > b;
+}
+
+template <typename T> bool operator<=(const object<T>& a, zx_handle_t b) {
+    return !(a.get() > b);
+}
+
+template <typename T> bool operator>=(const object<T>& a, zx_handle_t b) {
+    return !(a.get() < b);
+}
+
+// Wraps a handle to an object to provide type-safe access to its operations
+// but does not take ownership of it.  The handle is not closed when the
+// wrapper is destroyed.
+//
+// All use of unowned<object<T>> as an object<T> is via a dereference operator,
+// as illustrated below:
+//
+// void do_something(const zx::event& event);
+//
+// void example(zx_handle_t event_handle) {
+//     do_something(*zx::unowned<event>(event_handle));
+// }
+//
+// Convenience aliases are provided for all object types, for example:
+//
+// zx::unowned_event(handle)->signal(..)
+template <typename T>
+class unowned final {
+public:
+    explicit unowned(zx_handle_t h) : value_(h) {}
+    explicit unowned(const T& owner) : unowned(owner.get()) {}
+    explicit unowned(unowned& other) : unowned(*other) {}
+    constexpr unowned() = default;
+    unowned(unowned&& other) = default;
+
+    ~unowned() { release_value(); }
+
+    unowned& operator=(unowned& other) {
+        *this = unowned(other);
+        return *this;
+    }
+    unowned& operator=(unowned&& other) {
+        release_value();
+        value_ = static_cast<T&&>(other.value_);
+        return *this;
+    }
+
+    const T& operator*() const { return value_; }
+    const T* operator->() const { return &value_; }
+
+private:
+    void release_value() {
+        zx_handle_t h = value_.release();
+        static_cast<void>(h);
+    }
+
+    T value_;
+};
+
+} // namespace zx
+
+#endif  // LIB_ZX_OBJECT_H_
diff --git a/pkg/zx/include/lib/zx/object_traits.h b/pkg/zx/include/lib/zx/object_traits.h
new file mode 100644
index 0000000..f5a62c6
--- /dev/null
+++ b/pkg/zx/include/lib/zx/object_traits.h
@@ -0,0 +1,111 @@
+// Copyright 2016 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef LIB_ZX_OBJECT_TRAITS_H_
+#define LIB_ZX_OBJECT_TRAITS_H_
+
+namespace zx {
+
+class channel;
+class eventpair;
+class log;
+class socket;
+class vmo;
+class vmar;
+class port;
+class guest;
+class fifo;
+class interrupt;
+class pmt;
+
+// The default traits supports:
+// - event
+// - thread
+// - process
+// - job
+// - vmo
+// - bti
+// - resource
+// - timer
+// - iommu
+template <typename T> struct object_traits {
+    static constexpr bool supports_duplication = true;
+    static constexpr bool supports_user_signal = true;
+    static constexpr bool supports_wait = true;
+    static constexpr bool has_peer_handle = false;
+};
+
+template <> struct object_traits<channel> {
+    static constexpr bool supports_duplication = false;
+    static constexpr bool supports_user_signal = true;
+    static constexpr bool supports_wait = true;
+    static constexpr bool has_peer_handle = true;
+};
+
+template <> struct object_traits<eventpair> {
+    static constexpr bool supports_duplication = true;
+    static constexpr bool supports_user_signal = true;
+    static constexpr bool supports_wait = true;
+    static constexpr bool has_peer_handle = true;
+};
+
+template <> struct object_traits<fifo> {
+    static constexpr bool supports_duplication = true;
+    static constexpr bool supports_user_signal = true;
+    static constexpr bool supports_wait = true;
+    static constexpr bool has_peer_handle = true;
+};
+
+template <> struct object_traits<log> {
+    static constexpr bool supports_duplication = true;
+    static constexpr bool supports_user_signal = true;
+    static constexpr bool supports_wait = true;
+    static constexpr bool has_peer_handle = false;
+};
+
+template <> struct object_traits<pmt> {
+    static constexpr bool supports_duplication = false;
+    static constexpr bool supports_user_signal = false;
+    static constexpr bool supports_wait = false;
+    static constexpr bool has_peer_handle = false;
+};
+
+template <> struct object_traits<socket> {
+    static constexpr bool supports_duplication = true;
+    static constexpr bool supports_user_signal = true;
+    static constexpr bool supports_wait = true;
+    static constexpr bool has_peer_handle = true;
+};
+
+template <> struct object_traits<port> {
+    static constexpr bool supports_duplication = true;
+    static constexpr bool supports_user_signal = false;
+    static constexpr bool supports_wait = false;
+    static constexpr bool has_peer_handle = false;
+};
+
+template <> struct object_traits<vmar> {
+    static constexpr bool supports_duplication = true;
+    static constexpr bool supports_user_signal = false;
+    static constexpr bool supports_wait = false;
+    static constexpr bool has_peer_handle = false;
+};
+
+template <> struct object_traits<interrupt> {
+    static constexpr bool supports_duplication = true;
+    static constexpr bool supports_user_signal = false;
+    static constexpr bool supports_wait = true;
+    static constexpr bool has_peer_handle = false;
+};
+
+template <> struct object_traits<guest> {
+    static constexpr bool supports_duplication = true;
+    static constexpr bool supports_user_signal = false;
+    static constexpr bool supports_wait = false;
+    static constexpr bool has_peer_handle = false;
+};
+
+} // namespace zx
+
+#endif  // LIB_ZX_OBJECT_TRAITS_H_
diff --git a/pkg/zx/include/lib/zx/pmt.h b/pkg/zx/include/lib/zx/pmt.h
new file mode 100644
index 0000000..404235a
--- /dev/null
+++ b/pkg/zx/include/lib/zx/pmt.h
@@ -0,0 +1,37 @@
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef LIB_ZX_PMT_H_
+#define LIB_ZX_PMT_H_
+
+#include <lib/zx/handle.h>
+#include <lib/zx/object.h>
+
+namespace zx {
+
+class pmt : public object<pmt> {
+public:
+    static constexpr zx_obj_type_t TYPE = ZX_OBJ_TYPE_PMT;
+
+    constexpr pmt() = default;
+
+    explicit pmt(zx_handle_t value) : object(value) {}
+
+    explicit pmt(handle&& h) : object(h.release()) {}
+
+    pmt(pmt&& other) : object(other.release()) {}
+
+    pmt& operator=(pmt&& other) {
+        reset(other.release());
+        return *this;
+    }
+
+    zx_status_t unpin() { return zx_pmt_unpin(release()); }
+};
+
+using unowned_pmt = unowned<pmt>;
+
+} // namespace zx
+
+#endif  // LIB_ZX_PMT_H_
diff --git a/pkg/zx/include/lib/zx/port.h b/pkg/zx/include/lib/zx/port.h
new file mode 100644
index 0000000..ef607ec
--- /dev/null
+++ b/pkg/zx/include/lib/zx/port.h
@@ -0,0 +1,50 @@
+// Copyright 2016 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef LIB_ZX_PORT_H_
+#define LIB_ZX_PORT_H_
+
+#include <lib/zx/handle.h>
+#include <lib/zx/object.h>
+#include <lib/zx/time.h>
+
+namespace zx {
+
+class port : public object<port> {
+public:
+    static constexpr zx_obj_type_t TYPE = ZX_OBJ_TYPE_PORT;
+
+    constexpr port() = default;
+
+    explicit port(zx_handle_t value) : object(value) {}
+
+    explicit port(handle&& h) : object(h.release()) {}
+
+    port(port&& other) : object(other.release()) {}
+
+    port& operator=(port&& other) {
+        reset(other.release());
+        return *this;
+    }
+
+    static zx_status_t create(uint32_t options, port* result);
+
+    zx_status_t queue(const zx_port_packet_t* packet) const {
+        return zx_port_queue(get(), packet);
+    }
+
+    zx_status_t wait(zx::time deadline, zx_port_packet_t* packet) const {
+        return zx_port_wait(get(), deadline.get(), packet);
+    }
+
+    zx_status_t cancel(const object_base& source, uint64_t key) const {
+        return zx_port_cancel(get(), source.get(), key);
+    }
+};
+
+using unowned_port = unowned<port>;
+
+} // namespace zx
+
+#endif  // LIB_ZX_PORT_H_
diff --git a/pkg/zx/include/lib/zx/process.h b/pkg/zx/include/lib/zx/process.h
new file mode 100644
index 0000000..c3fe348
--- /dev/null
+++ b/pkg/zx/include/lib/zx/process.h
@@ -0,0 +1,67 @@
+// Copyright 2016 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef LIB_ZX_PROCESS_H_
+#define LIB_ZX_PROCESS_H_
+
+#include <lib/zx/object.h>
+#include <lib/zx/task.h>
+#include <lib/zx/vmar.h>
+#include <lib/zx/vmo.h>
+#include <zircon/process.h>
+
+namespace zx {
+class job;
+class thread;
+
+class process : public task<process> {
+public:
+    static constexpr zx_obj_type_t TYPE = ZX_OBJ_TYPE_PROCESS;
+
+    constexpr process() = default;
+
+    explicit process(zx_handle_t value) : task(value) {}
+
+    explicit process(handle&& h) : task(h.release()) {}
+
+    process(process&& other) : task(other.release()) {}
+
+    process& operator=(process&& other) {
+        reset(other.release());
+        return *this;
+    }
+
+    // Rather than creating a process directly with this syscall,
+    // consider using the launchpad library, which properly sets up
+    // the many details of creating a process beyond simply creating
+    // the kernel structure.
+    static zx_status_t create(const job& job, const char* name, uint32_t name_len,
+                              uint32_t flags, process* proc, vmar* root_vmar);
+
+    zx_status_t start(const thread& thread_handle, uintptr_t entry,
+                      uintptr_t stack, handle arg_handle, uintptr_t arg2) const;
+
+    zx_status_t read_memory(uintptr_t vaddr, void* buffer, size_t len, size_t* actual) const {
+        return zx_process_read_memory(get(), vaddr, buffer, len, actual);
+    }
+
+    zx_status_t write_memory(uintptr_t vaddr, const void* buffer, size_t len, size_t* actual) {
+        return zx_process_write_memory(get(), vaddr, buffer, len, actual);
+    }
+
+    // Provide strongly-typed overload, in addition to get_child(handle*).
+    using task<process>::get_child;
+    zx_status_t get_child(uint64_t koid, zx_rights_t rights,
+                          thread* result) const;
+
+    static inline unowned<process> self() {
+        return unowned<process>(zx_process_self());
+    }
+};
+
+using unowned_process = unowned<process>;
+
+} // namespace zx
+
+#endif  // LIB_ZX_PROCESS_H_
diff --git a/pkg/zx/include/lib/zx/profile.h b/pkg/zx/include/lib/zx/profile.h
new file mode 100644
index 0000000..ddc3fe3
--- /dev/null
+++ b/pkg/zx/include/lib/zx/profile.h
@@ -0,0 +1,38 @@
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef LIB_ZX_PROFILE_H_
+#define LIB_ZX_PROFILE_H_
+
+#include <lib/zx/handle.h>
+#include <lib/zx/object.h>
+#include <lib/zx/resource.h>
+
+namespace zx {
+
+class profile : public object<profile> {
+public:
+    static constexpr zx_obj_type_t TYPE = ZX_OBJ_TYPE_LOG;
+
+    constexpr profile() = default;
+
+    explicit profile(zx_handle_t value) : object(value) {}
+
+    explicit profile(handle&& h) : object(h.release()) {}
+
+    profile(profile&& other) : object(other.release()) {}
+
+    profile& operator=(profile&& other) {
+        reset(other.release());
+        return *this;
+    }
+
+    static zx_status_t create(const resource& resource, const zx_profile_info_t* info, profile* result);
+};
+
+using unowned_profile = unowned<profile>;
+
+} // namespace zx
+
+#endif  // LIB_ZX_PROFILE_H_
diff --git a/pkg/zx/include/lib/zx/resource.h b/pkg/zx/include/lib/zx/resource.h
new file mode 100644
index 0000000..4909868
--- /dev/null
+++ b/pkg/zx/include/lib/zx/resource.h
@@ -0,0 +1,43 @@
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef LIB_ZX_RESOURCE_H_
+#define LIB_ZX_RESOURCE_H_
+
+#include <lib/zx/handle.h>
+#include <lib/zx/object.h>
+
+namespace zx {
+
+class resource : public object<resource> {
+public:
+    static constexpr zx_obj_type_t TYPE = ZX_OBJ_TYPE_RESOURCE;
+
+    constexpr resource() = default;
+
+    explicit resource(zx_handle_t value) : object(value) {}
+
+    explicit resource(handle&& h) : object(h.release()) {}
+
+    resource(resource&& other) : object(other.release()) {}
+
+    resource& operator=(resource&& other) {
+        reset(other.release());
+        return *this;
+    }
+
+    static zx_status_t create(const resource& parent,
+                              uint32_t options,
+                              uint64_t base,
+                              size_t len,
+                              const char* name,
+                              size_t namelen,
+                              resource* result);
+};
+
+using unowned_resource = unowned<resource>;
+
+} // namespace zx
+
+#endif  // LIB_ZX_RESOURCE_H_
diff --git a/pkg/zx/include/lib/zx/socket.h b/pkg/zx/include/lib/zx/socket.h
new file mode 100644
index 0000000..180e1fa
--- /dev/null
+++ b/pkg/zx/include/lib/zx/socket.h
@@ -0,0 +1,65 @@
+// Copyright 2016 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef LIB_ZX_SOCKET_H_
+#define LIB_ZX_SOCKET_H_
+
+#include <lib/zx/handle.h>
+#include <lib/zx/object.h>
+
+namespace zx {
+
+class socket : public object<socket> {
+public:
+    static constexpr zx_obj_type_t TYPE = ZX_OBJ_TYPE_SOCKET;
+
+    constexpr socket() = default;
+
+    explicit socket(zx_handle_t value) : object(value) {}
+
+    explicit socket(handle&& h) : object(h.release()) {}
+
+    socket(socket&& other) : object(other.release()) {}
+
+    socket& operator=(socket&& other) {
+        reset(other.release());
+        return *this;
+    }
+
+    static zx_status_t create(uint32_t options, socket* endpoint0,
+                              socket* endpoint1);
+
+    zx_status_t write(uint32_t options, const void* buffer, size_t len,
+                      size_t* actual) const {
+        return zx_socket_write(get(), options, buffer, len, actual);
+    }
+
+    zx_status_t read(uint32_t options, void* buffer, size_t len,
+                     size_t* actual) const {
+        return zx_socket_read(get(), options, buffer, len, actual);
+    }
+
+    zx_status_t share(socket socket_to_share) const {
+        return zx_socket_share(get(), socket_to_share.release());
+    }
+
+    zx_status_t accept(socket* out_socket) const {
+        // We use a temporary to handle the case where |this| and |out_socket|
+        // are aliased.
+        socket result;
+        zx_status_t status = zx_socket_accept(get(), result.reset_and_get_address());
+        out_socket->reset(result.release());
+        return status;
+    }
+
+    zx_status_t shutdown(uint32_t options) const {
+        return zx_socket_shutdown(get(), options);
+    }
+};
+
+using unowned_socket = unowned<socket>;
+
+} // namespace zx
+
+#endif  // LIB_ZX_SOCKET_H_
diff --git a/pkg/zx/include/lib/zx/suspend_token.h b/pkg/zx/include/lib/zx/suspend_token.h
new file mode 100644
index 0000000..8eba2df
--- /dev/null
+++ b/pkg/zx/include/lib/zx/suspend_token.h
@@ -0,0 +1,35 @@
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef LIB_ZX_SUSPEND_TOKEN_H_
+#define LIB_ZX_SUSPEND_TOKEN_H_
+
+#include <lib/zx/handle.h>
+#include <lib/zx/object.h>
+
+namespace zx {
+
+// The only thing you can do with a suspend token is close it (which will
+// resume the thread).
+class suspend_token : public object<suspend_token> {
+public:
+    static constexpr zx_obj_type_t TYPE = ZX_OBJ_TYPE_SUSPEND_TOKEN;
+
+    constexpr suspend_token() = default;
+
+    explicit suspend_token(zx_handle_t value) : object<suspend_token>(value) {}
+
+    explicit suspend_token(handle&& h) : object<suspend_token>(h.release()) {}
+
+    suspend_token(suspend_token&& other) : object<suspend_token>(other.release()) {}
+
+    suspend_token& operator=(suspend_token&& other) {
+        reset(other.release());
+        return *this;
+    }
+};
+
+} // namespace zx
+
+#endif  // LIB_ZX_SUSPEND_TOKEN_H_
diff --git a/pkg/zx/include/lib/zx/task.h b/pkg/zx/include/lib/zx/task.h
new file mode 100644
index 0000000..a3bc20d
--- /dev/null
+++ b/pkg/zx/include/lib/zx/task.h
@@ -0,0 +1,51 @@
+// Copyright 2016 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef LIB_ZX_TASK_H_
+#define LIB_ZX_TASK_H_
+
+#include <lib/zx/handle.h>
+#include <lib/zx/object.h>
+#include <lib/zx/suspend_token.h>
+
+namespace zx {
+
+class port;
+class suspend_token;
+
+template <typename T = void> class task : public object<T> {
+public:
+    constexpr task() = default;
+
+    explicit task(zx_handle_t value) : object<T>(value) {}
+
+    explicit task(handle&& h) : object<T>(h.release()) {}
+
+    task(task&& other) : object<T>(other.release()) {}
+
+    zx_status_t bind_exception_port(
+            const object<port>& port, uint64_t key, uint32_t options) const {
+        return zx_task_bind_exception_port(object<T>::get(), port.get(), key, options);
+    }
+
+    zx_status_t kill() const { return zx_task_kill(object<T>::get()); }
+
+    // Deprecated: Use the variant that takes a suspend_token.
+    zx_status_t suspend() const { return zx_task_suspend(object<T>::get()); }
+
+    zx_status_t suspend(suspend_token* result) const {
+        // Assume |result| must refer to a different container than |this|, due
+        // to strict aliasing.
+        return zx_task_suspend_token(
+            object<T>::get(), result->reset_and_get_address());
+    }
+
+    zx_status_t resume_from_exception(const object<port>& port, uint32_t options) const {
+        return zx_task_resume_from_exception(object<T>::get(), port.get(), options);
+    }
+};
+
+} // namespace zx
+
+#endif  // LIB_ZX_TASK_H_
diff --git a/pkg/zx/include/lib/zx/thread.h b/pkg/zx/include/lib/zx/thread.h
new file mode 100644
index 0000000..eabf3ed
--- /dev/null
+++ b/pkg/zx/include/lib/zx/thread.h
@@ -0,0 +1,72 @@
+// Copyright 2016 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef LIB_ZX_THREAD_H_
+#define LIB_ZX_THREAD_H_
+
+#include <lib/zx/object.h>
+#include <lib/zx/task.h>
+#include <zircon/process.h>
+
+namespace zx {
+class process;
+
+class thread : public task<thread> {
+public:
+    static constexpr zx_obj_type_t TYPE = ZX_OBJ_TYPE_THREAD;
+
+    constexpr thread() = default;
+
+    explicit thread(zx_handle_t value)
+        : task(value) {}
+
+    explicit thread(handle&& h)
+        : task(h.release()) {}
+
+    thread(thread&& other)
+        : task(other.release()) {}
+
+    thread& operator=(thread&& other) {
+        reset(other.release());
+        return *this;
+    }
+
+    // Rather than creating a thread directly with this syscall, consider using
+    // std::thread or thrd_create, which properly integrates with the
+    // thread-local data structures in libc.
+    static zx_status_t create(const process& process, const char* name,
+                              uint32_t name_len, uint32_t flags,
+                              thread* result);
+
+    // The first variant maps exactly to the syscall and can be used for
+    // launching threads in remote processes. The second variant is for
+    // conveniently launching threads in the current process.
+    zx_status_t start(uintptr_t thread_entry, uintptr_t stack, uintptr_t arg1,
+                      uintptr_t arg2) const {
+        return zx_thread_start(get(), thread_entry, stack, arg1, arg2);
+    }
+    zx_status_t start(void (*thread_entry)(uintptr_t arg1, uintptr_t arg2),
+                      void* stack, uintptr_t arg1, uintptr_t arg2) {
+        return zx_thread_start(get(),
+                               reinterpret_cast<uintptr_t>(thread_entry),
+                               reinterpret_cast<uintptr_t>(stack), arg1, arg2);
+    }
+
+    zx_status_t read_state(uint32_t kind, void* buffer, size_t len) const {
+        return zx_thread_read_state(get(), kind, buffer, len);
+    }
+    zx_status_t write_state(uint32_t kind, const void* buffer, size_t len) {
+        return zx_thread_write_state(get(), kind, buffer, len);
+    }
+
+    static inline unowned<thread> self() {
+        return unowned<thread>(zx_thread_self());
+    }
+};
+
+using unowned_thread = unowned<thread>;
+
+} // namespace zx
+
+#endif  // LIB_ZX_THREAD_H_
diff --git a/pkg/zx/include/lib/zx/time.h b/pkg/zx/include/lib/zx/time.h
new file mode 100644
index 0000000..101e057
--- /dev/null
+++ b/pkg/zx/include/lib/zx/time.h
@@ -0,0 +1,253 @@
+// Copyright 2016 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef LIB_ZX_TIME_H_
+#define LIB_ZX_TIME_H_
+
+#include <stdint.h>
+#include <zircon/compiler.h>
+#include <zircon/syscalls.h>
+#include <zircon/time.h>
+
+namespace zx {
+
+class duration {
+public:
+    constexpr duration() = default;
+
+    explicit constexpr duration(zx_duration_t value)
+        : value_(value) {}
+
+    static constexpr duration infinite() { return duration(ZX_TIME_INFINITE); }
+
+    static constexpr duration infinite_past() { return duration(ZX_TIME_INFINITE_PAST); }
+
+    constexpr zx_duration_t get() const { return value_; }
+
+    constexpr duration operator+(duration other) const {
+        return duration(zx_duration_add_duration(value_, other.value_));
+    }
+
+    constexpr duration operator-(duration other) const {
+        return duration(zx_duration_sub_duration(value_, other.value_));
+    }
+
+    constexpr duration operator*(int64_t multiplier) const {
+        return duration(zx_duration_mul_int64(value_, multiplier));
+    }
+
+    constexpr duration operator/(int64_t divisor) const {
+        return duration(value_ / divisor);
+    }
+
+    constexpr duration operator%(duration divisor) const {
+        return duration(value_ % divisor.value_);
+    }
+
+    constexpr int64_t operator/(duration other) const {
+        return value_ / other.value_;
+    }
+
+    constexpr duration& operator+=(duration other) {
+        value_ = zx_duration_add_duration(value_, other.value_);
+        return *this;
+    }
+
+    constexpr duration& operator-=(duration other) {
+        value_ = zx_duration_sub_duration(value_, other.value_);
+        return *this;
+    }
+
+    constexpr duration& operator*=(int64_t multiplier) {
+        value_ = zx_duration_mul_int64(value_, multiplier);
+        return *this;
+    }
+
+    constexpr duration& operator/=(int64_t divisor) {
+        value_ /= divisor;
+        return *this;
+    }
+
+    constexpr bool operator==(duration other) const { return value_ == other.value_; }
+    constexpr bool operator!=(duration other) const { return value_ != other.value_; }
+    constexpr bool operator<(duration other) const { return value_ < other.value_; }
+    constexpr bool operator<=(duration other) const { return value_ <= other.value_; }
+    constexpr bool operator>(duration other) const { return value_ > other.value_; }
+    constexpr bool operator>=(duration other) const { return value_ >= other.value_; }
+
+    constexpr int64_t to_nsecs() const { return value_; }
+
+    constexpr int64_t to_usecs() const { return value_ / ZX_USEC(1); }
+
+    constexpr int64_t to_msecs() const { return value_ / ZX_MSEC(1); }
+
+    constexpr int64_t to_secs() const { return value_ / ZX_SEC(1); }
+
+    constexpr int64_t to_mins() const { return value_ / ZX_MIN(1); }
+
+    constexpr int64_t to_hours() const { return value_ / ZX_HOUR(1); }
+
+private:
+    zx_duration_t value_ = 0;
+};
+
+class ticks {
+public:
+    constexpr ticks() = default;
+
+    explicit constexpr ticks(zx_ticks_t value) : value_(value) {}
+
+    // Constructs a tick object for the current tick counter in the system.
+    static ticks now() { return ticks(zx_ticks_get()); }
+
+    // Returns the number of ticks contained within one second.
+    static ticks per_second() { return ticks(zx_ticks_per_second()); }
+
+    // Acquires the number of ticks contained within this object.
+    constexpr zx_ticks_t get() const { return value_; }
+
+    constexpr ticks operator+(ticks other) const {
+        return ticks(value_ + other.value_);
+    }
+
+    constexpr ticks operator-(ticks other) const {
+        return ticks(value_ - other.value_);
+    }
+
+    constexpr ticks operator*(uint64_t multiplier) const {
+        return ticks(value_ * multiplier);
+    }
+
+    constexpr ticks operator/(uint64_t divisor) const {
+        return ticks(value_ / divisor);
+    }
+
+    constexpr uint64_t operator/(ticks other) const {
+        return value_ / other.value_;
+    }
+
+    constexpr ticks& operator+=(ticks other) {
+        value_ += other.value_;
+        return *this;
+    }
+
+    constexpr ticks& operator-=(ticks other) {
+        value_ -= other.value_;
+        return *this;
+    }
+
+    constexpr ticks& operator*=(uint64_t multiplier) {
+        value_ *= multiplier;
+        return *this;
+    }
+
+    constexpr ticks& operator/=(uint64_t divisor) {
+        value_ /= divisor;
+        return *this;
+    }
+
+    constexpr bool operator==(ticks other) const { return value_ == other.value_; }
+    constexpr bool operator!=(ticks other) const { return value_ != other.value_; }
+    constexpr bool operator<(ticks other) const { return value_ < other.value_; }
+    constexpr bool operator<=(ticks other) const { return value_ <= other.value_; }
+    constexpr bool operator>(ticks other) const { return value_ > other.value_; }
+    constexpr bool operator>=(ticks other) const { return value_ >= other.value_; }
+
+private:
+    zx_ticks_t value_ = 0;
+};
+
+template <zx_clock_t kClockId>
+class basic_time {
+public:
+    constexpr basic_time() = default;
+
+    explicit constexpr basic_time(zx_time_t value) : value_(value) {}
+
+    static constexpr basic_time<kClockId> infinite() {
+        return basic_time<kClockId>(ZX_TIME_INFINITE);
+    }
+
+    static constexpr basic_time<kClockId> infinite_past() {
+        return basic_time<kClockId>(ZX_TIME_INFINITE_PAST);
+    }
+
+    constexpr zx_time_t get() const { return value_; }
+
+    zx_time_t* get_address() { return &value_; }
+
+    constexpr duration operator-(basic_time<kClockId> other) const {
+        return duration(zx_time_sub_time(value_, other.value_));
+    }
+
+    constexpr basic_time<kClockId> operator+(duration delta) const {
+        return basic_time<kClockId>(zx_time_add_duration(value_, delta.get()));
+    }
+
+    constexpr basic_time<kClockId> operator-(duration delta) const {
+        return basic_time<kClockId>(zx_time_sub_duration(value_, delta.get()));
+    }
+
+    constexpr basic_time<kClockId>& operator+=(duration delta) {
+      value_ = zx_time_add_duration(value_, delta.get());
+      return *this;
+    }
+
+    constexpr basic_time<kClockId>& operator-=(duration delta) {
+      value_ = zx_time_sub_duration(value_, delta.get());
+      return *this;
+    }
+
+    constexpr bool operator==(basic_time<kClockId> other) const { return value_ == other.value_; }
+    constexpr bool operator!=(basic_time<kClockId> other) const { return value_ != other.value_; }
+    constexpr bool operator<(basic_time<kClockId> other) const { return value_ < other.value_; }
+    constexpr bool operator<=(basic_time<kClockId> other) const { return value_ <= other.value_; }
+    constexpr bool operator>(basic_time<kClockId> other) const { return value_ > other.value_; }
+    constexpr bool operator>=(basic_time<kClockId> other) const { return value_ >= other.value_; }
+
+private:
+    zx_time_t value_ = 0;
+};
+
+using time = basic_time<ZX_CLOCK_MONOTONIC>;
+using time_utc = basic_time<ZX_CLOCK_UTC>;
+using time_thread = basic_time<ZX_CLOCK_THREAD>;
+
+class clock {
+public:
+    clock() = delete;
+
+    template <zx_clock_t kClockId>
+    static zx_status_t get(basic_time<kClockId>* result) {
+        return zx_clock_get_new(kClockId, result->get_address());
+    }
+
+    static time get_monotonic() {
+      return time(zx_clock_get_monotonic());
+    }
+};
+
+constexpr inline duration nsec(int64_t n) { return duration(ZX_NSEC(n)); }
+
+constexpr inline duration usec(int64_t n) { return duration(ZX_USEC(n)); }
+
+constexpr inline duration msec(int64_t n) { return duration(ZX_MSEC(n)); }
+
+constexpr inline duration sec(int64_t n) { return duration(ZX_SEC(n)); }
+
+constexpr inline duration min(int64_t n) { return duration(ZX_MIN(n)); }
+
+constexpr inline duration hour(int64_t n) { return duration(ZX_HOUR(n)); }
+
+inline zx_status_t nanosleep(zx::time deadline) {
+    return zx_nanosleep(deadline.get());
+}
+
+inline time deadline_after(zx::duration nanoseconds) {
+    return time(zx_deadline_after(nanoseconds.get()));
+}
+
+} // namespace zx
+
+#endif  // LIB_ZX_TIME_H_
diff --git a/pkg/zx/include/lib/zx/timer.h b/pkg/zx/include/lib/zx/timer.h
new file mode 100644
index 0000000..d7990ac
--- /dev/null
+++ b/pkg/zx/include/lib/zx/timer.h
@@ -0,0 +1,47 @@
+// Copyright 2017 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef LIB_ZX_TIMER_H_
+#define LIB_ZX_TIMER_H_
+
+#include <lib/zx/handle.h>
+#include <lib/zx/object.h>
+
+#include <zircon/types.h>
+
+namespace zx {
+
+class timer : public object<timer> {
+public:
+    static constexpr zx_obj_type_t TYPE = ZX_OBJ_TYPE_TIMER;
+
+    constexpr timer() = default;
+
+    explicit timer(zx_handle_t value) : object(value) {}
+
+    explicit timer(handle&& h) : object(h.release()) {}
+
+    timer(timer&& other) : object(other.release()) {}
+
+    timer& operator=(timer&& other) {
+        reset(other.release());
+        return *this;
+    }
+
+    static zx_status_t create(uint32_t options, zx_clock_t clock_id, timer* result);
+
+    zx_status_t set(zx::time deadline, zx::duration slack) const {
+        return zx_timer_set(get(), deadline.get(), slack.get());
+    }
+
+    zx_status_t cancel() const {
+        return zx_timer_cancel(get());
+    }
+};
+
+using unowned_timer = unowned<timer>;
+
+} // namespace zx
+
+#endif  // LIB_ZX_TIMER_H_
diff --git a/pkg/zx/include/lib/zx/vcpu.h b/pkg/zx/include/lib/zx/vcpu.h
new file mode 100644
index 0000000..dac3f3a
--- /dev/null
+++ b/pkg/zx/include/lib/zx/vcpu.h
@@ -0,0 +1,56 @@
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef LIB_ZX_VCPU_H_
+#define LIB_ZX_VCPU_H_
+
+#include <lib/zx/guest.h>
+#include <lib/zx/handle.h>
+#include <lib/zx/object.h>
+#include <zircon/syscalls/port.h>
+
+namespace zx {
+
+class vcpu : public object<vcpu> {
+public:
+    static constexpr zx_obj_type_t TYPE = ZX_OBJ_TYPE_VCPU;
+
+    constexpr vcpu() = default;
+
+    explicit vcpu(zx_handle_t value) : object(value) {}
+
+    explicit vcpu(handle&& h) : object(h.release()) {}
+
+    vcpu(vcpu&& other) : object(other.release()) {}
+
+    vcpu& operator=(vcpu&& other) {
+        reset(other.release());
+        return *this;
+    }
+
+    static zx_status_t create(const guest& guest, uint32_t options,
+                              zx_gpaddr_t entry, vcpu* result);
+
+    zx_status_t resume(zx_port_packet_t* packet) {
+        return zx_vcpu_resume(get(), packet);
+    }
+
+    zx_status_t interrupt(uint32_t interrupt) {
+        return zx_vcpu_interrupt(get(), interrupt);
+    }
+
+    zx_status_t read_state(uint32_t kind, void* buf, size_t len) const {
+        return zx_vcpu_read_state(get(), kind, buf, len);
+    }
+
+    zx_status_t write_state(uint32_t kind, const void* buf, size_t len) {
+        return zx_vcpu_write_state(get(), kind, buf, len);
+    }
+};
+
+using unowned_vcpu = unowned<vcpu>;
+
+} // namespace zx
+
+#endif  // LIB_ZX_VCPU_H_
diff --git a/pkg/zx/include/lib/zx/vmar.h b/pkg/zx/include/lib/zx/vmar.h
new file mode 100644
index 0000000..1553110
--- /dev/null
+++ b/pkg/zx/include/lib/zx/vmar.h
@@ -0,0 +1,62 @@
+// Copyright 2016 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef LIB_ZX_VMAR_H_
+#define LIB_ZX_VMAR_H_
+
+#include <lib/zx/object.h>
+#include <lib/zx/vmo.h>
+#include <zircon/process.h>
+
+namespace zx {
+
+// A wrapper for handles to VMARs.  Note that vmar::~vmar() does not execute
+// vmar::destroy(), it just closes the handle.
+class vmar : public object<vmar> {
+public:
+    static constexpr zx_obj_type_t TYPE = ZX_OBJ_TYPE_VMAR;
+
+    constexpr vmar() = default;
+
+    explicit vmar(zx_handle_t value) : object(value) {}
+
+    explicit vmar(handle&& h) : object(h.release()) {}
+
+    vmar(vmar&& other) : vmar(other.release()) {}
+
+    vmar& operator=(vmar&& other) {
+        reset(other.release());
+        return *this;
+    }
+
+    zx_status_t map(size_t vmar_offset, const vmo& vmo_handle, uint64_t vmo_offset,
+                    size_t len, zx_vm_option_t options, uintptr_t* ptr) const {
+        return zx_vmar_map(get(), options, vmar_offset, vmo_handle.get(), vmo_offset, len, ptr);
+    }
+
+    zx_status_t unmap(uintptr_t address, size_t len) const {
+        return zx_vmar_unmap(get(), address, len);
+    }
+
+    zx_status_t protect(uintptr_t address, size_t len, zx_vm_option_t prot) const {
+        return zx_vmar_protect(get(), prot, address, len);
+    }
+
+    zx_status_t destroy() const {
+        return zx_vmar_destroy(get());
+    }
+
+    zx_status_t allocate(size_t offset, size_t size, uint32_t flags,
+                         vmar* child, uintptr_t* child_addr) const;
+
+    static inline unowned<vmar> root_self() {
+        return unowned<vmar>(zx_vmar_root_self());
+    }
+};
+
+using unowned_vmar = unowned<vmar>;
+
+} // namespace zx
+
+#endif  // LIB_ZX_VMAR_H_
diff --git a/pkg/zx/include/lib/zx/vmo.h b/pkg/zx/include/lib/zx/vmo.h
new file mode 100644
index 0000000..82e2cab
--- /dev/null
+++ b/pkg/zx/include/lib/zx/vmo.h
@@ -0,0 +1,89 @@
+// Copyright 2016 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef LIB_ZX_VMO_H_
+#define LIB_ZX_VMO_H_
+
+#include <lib/zx/handle.h>
+#include <lib/zx/object.h>
+#include <lib/zx/resource.h>
+
+namespace zx {
+
+class bti;
+
+class vmo : public object<vmo> {
+public:
+    static constexpr zx_obj_type_t TYPE = ZX_OBJ_TYPE_VMO;
+
+    constexpr vmo() = default;
+
+    explicit vmo(zx_handle_t value) : object(value) {}
+
+    explicit vmo(handle&& h) : object(h.release()) {}
+
+    vmo(vmo&& other) : object(other.release()) {}
+
+    vmo& operator=(vmo&& other) {
+        reset(other.release());
+        return *this;
+    }
+
+    static zx_status_t create(uint64_t size, uint32_t options, vmo* result);
+    static zx_status_t create_contiguous(
+        const bti& bti, size_t size, uint32_t alignment_log2, vmo* result);
+    static zx_status_t create_physical(
+        const resource& resource, zx_paddr_t paddr, size_t size, vmo* result);
+
+    zx_status_t read(void* data, uint64_t offset, size_t len) const {
+        return zx_vmo_read(get(), data, offset, len);
+    }
+
+    zx_status_t write(const void* data, uint64_t offset, size_t len) const {
+        return zx_vmo_write(get(), data, offset, len);
+    }
+
+    zx_status_t get_size(uint64_t* size) const {
+        return zx_vmo_get_size(get(), size);
+    }
+
+    zx_status_t set_size(uint64_t size) const {
+        return zx_vmo_set_size(get(), size);
+    }
+
+    zx_status_t clone(uint32_t options, uint64_t offset, uint64_t size,
+                      vmo* result) const {
+        // Allow for the caller aliasing |result| to |this|.
+        vmo h;
+        zx_status_t status = zx_vmo_clone(
+            get(), options, offset, size, h.reset_and_get_address());
+        result->reset(h.release());
+        return status;
+    }
+
+    zx_status_t op_range(uint32_t op, uint64_t offset, uint64_t size,
+                         void* buffer, size_t buffer_size) const {
+        return zx_vmo_op_range(get(), op, offset, size, buffer, buffer_size);
+    }
+
+    zx_status_t set_cache_policy(uint32_t cache_policy) {
+        return zx_vmo_set_cache_policy(get(), cache_policy);
+    }
+
+    zx_status_t replace_as_executable(const handle& vmex, vmo* result) {
+        zx_handle_t h = ZX_HANDLE_INVALID;
+        zx_status_t status = zx_vmo_replace_as_executable(value_, vmex.get(), &h);
+        // We store ZX_HANDLE_INVALID to value_ before calling reset on result
+        // in case result == this.
+        value_ = ZX_HANDLE_INVALID;
+        result->reset(h);
+        return status;
+    }
+};
+
+using unowned_vmo = unowned<vmo>;
+
+} // namespace zx
+
+#endif  // LIB_ZX_VMO_H_
diff --git a/pkg/zx/interrupt.cpp b/pkg/zx/interrupt.cpp
new file mode 100644
index 0000000..609406d
--- /dev/null
+++ b/pkg/zx/interrupt.cpp
@@ -0,0 +1,19 @@
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <lib/zx/interrupt.h>
+
+#include <zircon/syscalls.h>
+
+namespace zx {
+
+zx_status_t interrupt::create(const resource& resource, uint32_t vector,
+                              uint32_t options, interrupt* result) {
+    // Assume |result| uses a distinct container from |resource|, due to
+    // strict aliasing.
+    return zx_interrupt_create(
+        resource.get(), vector, options, result->reset_and_get_address());
+}
+
+} // namespace zx
diff --git a/pkg/zx/iommu.cpp b/pkg/zx/iommu.cpp
new file mode 100644
index 0000000..ad3c078
--- /dev/null
+++ b/pkg/zx/iommu.cpp
@@ -0,0 +1,16 @@
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <lib/zx/iommu.h>
+
+#include <zircon/syscalls.h>
+
+namespace zx {
+
+zx_status_t iommu::create(const resource& resource, uint32_t type, const void* desc,
+                          size_t desc_size, iommu* result) {
+    return zx_iommu_create(resource.get(), type, desc, desc_size, result->reset_and_get_address());
+}
+
+} // namespace zx
diff --git a/pkg/zx/job.cpp b/pkg/zx/job.cpp
new file mode 100644
index 0000000..6989589
--- /dev/null
+++ b/pkg/zx/job.cpp
@@ -0,0 +1,29 @@
+// Copyright 2016 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <lib/zx/job.h>
+
+#include <lib/zx/process.h>
+#include <zircon/syscalls.h>
+
+namespace zx {
+
+zx_status_t job::create(const job& parent, uint32_t flags, job* result) {
+    // Allow for aliasing of the same container to |result| and |parent|.
+    job h;
+    zx_status_t status =
+        zx_job_create(parent.get(), flags, h.reset_and_get_address());
+    result->reset(h.release());
+    return status;
+}
+
+zx_status_t job::get_child(uint64_t koid, zx_rights_t rights,
+                           process* result) const {
+    // Assume |result| and |this| are distinct containers, due to strict
+    // aliasing.
+    return zx_object_get_child(
+        value_, koid, rights, result->reset_and_get_address());
+}
+
+} // namespace zx
diff --git a/pkg/zx/log.cpp b/pkg/zx/log.cpp
new file mode 100644
index 0000000..4c06b36
--- /dev/null
+++ b/pkg/zx/log.cpp
@@ -0,0 +1,15 @@
+// Copyright 2016 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <lib/zx/log.h>
+
+#include <zircon/syscalls.h>
+
+namespace zx {
+
+zx_status_t log::create(uint32_t flags, log* result) {
+    return zx_debuglog_create(ZX_HANDLE_INVALID, flags, result->reset_and_get_address());
+}
+
+} // namespace zx
diff --git a/pkg/zx/meta.json b/pkg/zx/meta.json
new file mode 100644
index 0000000..27622e6
--- /dev/null
+++ b/pkg/zx/meta.json
@@ -0,0 +1,113 @@
+{
+  "banjo_deps": [], 
+  "deps": [], 
+  "fidl_deps": [], 
+  "files": [
+    "pkg/zx/bti.cpp", 
+    "pkg/zx/channel.cpp", 
+    "pkg/zx/debuglog.cpp", 
+    "pkg/zx/event.cpp", 
+    "pkg/zx/eventpair.cpp", 
+    "pkg/zx/fifo.cpp", 
+    "pkg/zx/guest.cpp", 
+    "pkg/zx/interrupt.cpp", 
+    "pkg/zx/iommu.cpp", 
+    "pkg/zx/job.cpp", 
+    "pkg/zx/log.cpp", 
+    "pkg/zx/port.cpp", 
+    "pkg/zx/process.cpp", 
+    "pkg/zx/profile.cpp", 
+    "pkg/zx/resource.cpp", 
+    "pkg/zx/socket.cpp", 
+    "pkg/zx/thread.cpp", 
+    "pkg/zx/timer.cpp", 
+    "pkg/zx/vcpu.cpp", 
+    "pkg/zx/vmar.cpp", 
+    "pkg/zx/vmo.cpp", 
+    "pkg/zx/include/lib/zx/bti.h", 
+    "pkg/zx/include/lib/zx/channel.h", 
+    "pkg/zx/include/lib/zx/debuglog.h", 
+    "pkg/zx/include/lib/zx/event.h", 
+    "pkg/zx/include/lib/zx/eventpair.h", 
+    "pkg/zx/include/lib/zx/fifo.h", 
+    "pkg/zx/include/lib/zx/guest.h", 
+    "pkg/zx/include/lib/zx/handle.h", 
+    "pkg/zx/include/lib/zx/interrupt.h", 
+    "pkg/zx/include/lib/zx/iommu.h", 
+    "pkg/zx/include/lib/zx/job.h", 
+    "pkg/zx/include/lib/zx/log.h", 
+    "pkg/zx/include/lib/zx/object.h", 
+    "pkg/zx/include/lib/zx/object_traits.h", 
+    "pkg/zx/include/lib/zx/pmt.h", 
+    "pkg/zx/include/lib/zx/port.h", 
+    "pkg/zx/include/lib/zx/process.h", 
+    "pkg/zx/include/lib/zx/profile.h", 
+    "pkg/zx/include/lib/zx/resource.h", 
+    "pkg/zx/include/lib/zx/socket.h", 
+    "pkg/zx/include/lib/zx/suspend_token.h", 
+    "pkg/zx/include/lib/zx/task.h", 
+    "pkg/zx/include/lib/zx/thread.h", 
+    "pkg/zx/include/lib/zx/time.h", 
+    "pkg/zx/include/lib/zx/timer.h", 
+    "pkg/zx/include/lib/zx/vcpu.h", 
+    "pkg/zx/include/lib/zx/vmar.h", 
+    "pkg/zx/include/lib/zx/vmo.h"
+  ], 
+  "headers": [
+    "pkg/zx/include/lib/zx/bti.h", 
+    "pkg/zx/include/lib/zx/channel.h", 
+    "pkg/zx/include/lib/zx/debuglog.h", 
+    "pkg/zx/include/lib/zx/event.h", 
+    "pkg/zx/include/lib/zx/eventpair.h", 
+    "pkg/zx/include/lib/zx/fifo.h", 
+    "pkg/zx/include/lib/zx/guest.h", 
+    "pkg/zx/include/lib/zx/handle.h", 
+    "pkg/zx/include/lib/zx/interrupt.h", 
+    "pkg/zx/include/lib/zx/iommu.h", 
+    "pkg/zx/include/lib/zx/job.h", 
+    "pkg/zx/include/lib/zx/log.h", 
+    "pkg/zx/include/lib/zx/object.h", 
+    "pkg/zx/include/lib/zx/object_traits.h", 
+    "pkg/zx/include/lib/zx/pmt.h", 
+    "pkg/zx/include/lib/zx/port.h", 
+    "pkg/zx/include/lib/zx/process.h", 
+    "pkg/zx/include/lib/zx/profile.h", 
+    "pkg/zx/include/lib/zx/resource.h", 
+    "pkg/zx/include/lib/zx/socket.h", 
+    "pkg/zx/include/lib/zx/suspend_token.h", 
+    "pkg/zx/include/lib/zx/task.h", 
+    "pkg/zx/include/lib/zx/thread.h", 
+    "pkg/zx/include/lib/zx/time.h", 
+    "pkg/zx/include/lib/zx/timer.h", 
+    "pkg/zx/include/lib/zx/vcpu.h", 
+    "pkg/zx/include/lib/zx/vmar.h", 
+    "pkg/zx/include/lib/zx/vmo.h"
+  ], 
+  "include_dir": "pkg/zx/include", 
+  "name": "zx", 
+  "root": "pkg/zx", 
+  "sources": [
+    "pkg/zx/bti.cpp", 
+    "pkg/zx/channel.cpp", 
+    "pkg/zx/debuglog.cpp", 
+    "pkg/zx/event.cpp", 
+    "pkg/zx/eventpair.cpp", 
+    "pkg/zx/fifo.cpp", 
+    "pkg/zx/guest.cpp", 
+    "pkg/zx/interrupt.cpp", 
+    "pkg/zx/iommu.cpp", 
+    "pkg/zx/job.cpp", 
+    "pkg/zx/log.cpp", 
+    "pkg/zx/port.cpp", 
+    "pkg/zx/process.cpp", 
+    "pkg/zx/profile.cpp", 
+    "pkg/zx/resource.cpp", 
+    "pkg/zx/socket.cpp", 
+    "pkg/zx/thread.cpp", 
+    "pkg/zx/timer.cpp", 
+    "pkg/zx/vcpu.cpp", 
+    "pkg/zx/vmar.cpp", 
+    "pkg/zx/vmo.cpp"
+  ], 
+  "type": "cc_source_library"
+}
\ No newline at end of file
diff --git a/pkg/zx/port.cpp b/pkg/zx/port.cpp
new file mode 100644
index 0000000..f6ca294
--- /dev/null
+++ b/pkg/zx/port.cpp
@@ -0,0 +1,15 @@
+// Copyright 2016 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <lib/zx/port.h>
+
+#include <zircon/syscalls.h>
+
+namespace zx {
+
+zx_status_t port::create(uint32_t options, port* result) {
+    return zx_port_create(options, result->reset_and_get_address());
+}
+
+} // namespace zx
diff --git a/pkg/zx/process.cpp b/pkg/zx/process.cpp
new file mode 100644
index 0000000..c47fa79
--- /dev/null
+++ b/pkg/zx/process.cpp
@@ -0,0 +1,38 @@
+// Copyright 2016 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <lib/zx/process.h>
+
+#include <zircon/syscalls.h>
+
+#include <lib/zx/job.h>
+#include <lib/zx/thread.h>
+#include <lib/zx/vmar.h>
+
+namespace zx {
+
+zx_status_t process::create(const job& job, const char* name, uint32_t name_len,
+                            uint32_t flags, process* proc, vmar* vmar) {
+    // Assume |proc|, |vmar| and |job| must refer to different containers, due
+    // to strict aliasing.
+    return zx_process_create(
+        job.get(), name, name_len, flags, proc->reset_and_get_address(),
+        vmar->reset_and_get_address());
+}
+
+zx_status_t process::start(const thread& thread_handle, uintptr_t entry,
+                           uintptr_t stack, handle arg_handle,
+                           uintptr_t arg2) const {
+    return zx_process_start(get(), thread_handle.get(), entry, stack, arg_handle.release(), arg2);
+}
+
+zx_status_t process::get_child(uint64_t koid, zx_rights_t rights,
+                               thread* result) const {
+    // Assume |result| and |this| are distinct containers, due to strict
+    // aliasing.
+    return zx_object_get_child(
+        value_, koid, rights, result->reset_and_get_address());
+}
+
+} // namespace zx
diff --git a/pkg/zx/profile.cpp b/pkg/zx/profile.cpp
new file mode 100644
index 0000000..9e67647
--- /dev/null
+++ b/pkg/zx/profile.cpp
@@ -0,0 +1,16 @@
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <lib/zx/profile.h>
+
+#include <zircon/syscalls.h>
+#include <zircon/syscalls/profile.h>
+
+namespace zx {
+
+zx_status_t profile::create(const resource& resource, const zx_profile_info_t* info, profile* result) {
+    return zx_profile_create(resource.get(), info, result->reset_and_get_address());
+}
+
+} // namespace zx
diff --git a/pkg/zx/resource.cpp b/pkg/zx/resource.cpp
new file mode 100644
index 0000000..8f29841
--- /dev/null
+++ b/pkg/zx/resource.cpp
@@ -0,0 +1,25 @@
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <lib/zx/resource.h>
+
+#include <zircon/syscalls.h>
+
+namespace zx {
+
+zx_status_t resource::create(const resource& parent,
+                             uint32_t options,
+                             uint64_t base,
+                             size_t len,
+                             const char* name,
+                             size_t namelen,
+                             resource* result) {
+    resource h;
+    zx_status_t status = zx_resource_create(parent.get(), options, base, len, name, namelen,
+                                            h.reset_and_get_address());
+    result->reset(h.release());
+    return status;
+}
+
+} // namespace zx
diff --git a/pkg/zx/socket.cpp b/pkg/zx/socket.cpp
new file mode 100644
index 0000000..76f5071
--- /dev/null
+++ b/pkg/zx/socket.cpp
@@ -0,0 +1,25 @@
+// Copyright 2016 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <lib/zx/socket.h>
+
+#include <zircon/syscalls.h>
+
+namespace zx {
+
+zx_status_t socket::create(uint32_t flags, socket* endpoint0,
+                           socket* endpoint1) {
+    // Ensure aliasing of both out parameters to the same container
+    // has a well-defined result, and does not leak.
+    socket h0;
+    socket h1;
+    zx_status_t status = zx_socket_create(
+        flags, h0.reset_and_get_address(),
+        h1.reset_and_get_address());
+    endpoint0->reset(h0.release());
+    endpoint1->reset(h1.release());
+    return status;
+}
+
+} // namespace zx
diff --git a/pkg/zx/thread.cpp b/pkg/zx/thread.cpp
new file mode 100644
index 0000000..4b9ab4c
--- /dev/null
+++ b/pkg/zx/thread.cpp
@@ -0,0 +1,21 @@
+// Copyright 2016 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <lib/zx/thread.h>
+
+#include <zircon/syscalls.h>
+
+#include <lib/zx/process.h>
+
+namespace zx {
+
+zx_status_t thread::create(const process& process, const char* name,
+                           uint32_t name_len, uint32_t flags, thread* result) {
+    // Assume |result| and |process| must refer to different containers, due
+    // to strict aliasing.
+    return zx_thread_create(
+        process.get(), name, name_len, flags, result->reset_and_get_address());
+}
+
+} // namespace zx
diff --git a/pkg/zx/timer.cpp b/pkg/zx/timer.cpp
new file mode 100644
index 0000000..f67ddc3
--- /dev/null
+++ b/pkg/zx/timer.cpp
@@ -0,0 +1,15 @@
+// Copyright 2017 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <lib/zx/timer.h>
+
+#include <zircon/syscalls.h>
+
+namespace zx {
+
+zx_status_t timer::create(uint32_t options, zx_clock_t clock_id, timer* result) {
+    return zx_timer_create(options, clock_id, result->reset_and_get_address());
+}
+
+} // namespace zx
diff --git a/pkg/zx/vcpu.cpp b/pkg/zx/vcpu.cpp
new file mode 100644
index 0000000..5584a5e
--- /dev/null
+++ b/pkg/zx/vcpu.cpp
@@ -0,0 +1,19 @@
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <lib/zx/vcpu.h>
+
+#include <zircon/syscalls.h>
+
+namespace zx {
+
+zx_status_t vcpu::create(const guest& guest, uint32_t options,
+                         zx_gpaddr_t entry, vcpu* vcpu) {
+    // Assume |guest| and |vcpu| must refer to different containers, due to
+    // strict aliasing.
+    return zx_vcpu_create(guest.get(), options, entry,
+                          vcpu->reset_and_get_address());
+}
+
+} // namespace zx
diff --git a/pkg/zx/vmar.cpp b/pkg/zx/vmar.cpp
new file mode 100644
index 0000000..60148f2
--- /dev/null
+++ b/pkg/zx/vmar.cpp
@@ -0,0 +1,21 @@
+// Copyright 2016 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <lib/zx/vmar.h>
+
+#include <zircon/syscalls.h>
+
+namespace zx {
+
+zx_status_t vmar::allocate(size_t offset, size_t size, zx_vm_option_t options,
+                           vmar* child, uintptr_t* child_addr) const {
+    // Allow for aliasing of |child| to the same container as |this|.
+    vmar h;
+    zx_status_t status = zx_vmar_allocate(
+        get(), options, offset, size, h.reset_and_get_address(), child_addr);
+    child->reset(h.release());
+    return status;
+}
+
+} // namespace zx
diff --git a/pkg/zx/vmo.cpp b/pkg/zx/vmo.cpp
new file mode 100644
index 0000000..130c71f
--- /dev/null
+++ b/pkg/zx/vmo.cpp
@@ -0,0 +1,27 @@
+// Copyright 2016 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <lib/zx/vmo.h>
+#include <lib/zx/bti.h>
+
+#include <zircon/syscalls.h>
+
+namespace zx {
+
+zx_status_t vmo::create(uint64_t size, uint32_t options, vmo* result) {
+    return zx_vmo_create(size, options, result->reset_and_get_address());
+}
+
+zx_status_t vmo::create_contiguous(
+    const bti& bti, size_t size, uint32_t alignment_log2, vmo* result) {
+    return zx_vmo_create_contiguous(bti.get(), size, alignment_log2,
+                                    result->reset_and_get_address());
+}
+
+zx_status_t vmo::create_physical(
+    const resource& resource, zx_paddr_t paddr, size_t size, vmo* result) {
+    return zx_vmo_create_physical(resource.get(), paddr, size, result->reset_and_get_address());
+}
+
+} // namespace zx